# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0

load(
    "//rules:opentitan_test.bzl",
    "DEFAULT_TEST_FAILURE_MSG",
    "DEFAULT_TEST_SUCCESS_MSG",
    "cw310_params",
    "dv_params",
    "opentitan_functest",
    "verilator_params",
)
load("//rules:const.bzl", "CONST", "error_redact", "get_lc_items", "hex", "hex_digits", "lcv_hw_to_sw")
load(
    "//rules:opentitan.bzl",
    "bin_to_vmem",
    "opentitan_flash_binary",
    "opentitan_multislot_flash_binary",
    "scramble_flash_vmem",
)
load("//rules:manifest.bzl", "manifest")
load("//rules:opentitan_gdb_test.bzl", "IBEX_GPRS", "gdb_commands_copy_registers", "gdb_commands_restore_registers", "gdb_commands_set_registers", "get_gdb_readable_csr_names", "get_gdb_settable_csr_names", "opentitan_gdb_fpga_cw310_test")
load("//rules:otp.bzl", "STD_OTP_OVERLAYS", "otp_alert_digest", "otp_image", "otp_json", "otp_partition")
load("//rules:rom_e2e.bzl", "maybe_skip_in_ci")
load("//rules:splice.bzl", "bitstream_splice")
load("@bazel_skylib//lib:shell.bzl", "shell")
load("@bazel_skylib//lib:structs.bzl", "structs")

package(default_visibility = ["//visibility:public"])

MSG_TEMPLATE_BFV = "{}{}\r\n(?s:.*){}{}\r\n".format(
    CONST.SHUTDOWN.PREFIX.BFV,
    "{0}",
    CONST.SHUTDOWN.PREFIX.BFV,
    "{0}",
)

MSG_TEMPLATE_BFV_LCV = "{}{}\r\n{}{}\r\n(?s:.*){}{}\r\n{}{}\r\n".format(
    CONST.SHUTDOWN.PREFIX.BFV,
    "{0}",
    CONST.SHUTDOWN.PREFIX.LCV,
    "{1}",
    CONST.SHUTDOWN.PREFIX.BFV,
    "{0}",
    CONST.SHUTDOWN.PREFIX.LCV,
    "{1}",
)

MSG_STARTING_ROM_EXT = "Starting ROM_EXT"

MSG_PASS = "PASS!"

SLOTS = {
    "a": "0x0",
    "b": "0x80000",
}

# list of all the production/dev/test keys, finally list of all keys
# all the keys listed must be defined in /rules/opentitan.bzl
FAKE_TEST_KEYS = ["fake_test_key_0"]

FAKE_DEV_KEYS = ["fake_dev_key_0"]

FAKE_PROD_KEYS = ["fake_prod_key_0"]

FAKE_ALL_KEYS = FAKE_TEST_KEYS + FAKE_DEV_KEYS + FAKE_PROD_KEYS

# list of all acceptable keys in each LC state
# see secure boot documentation
LC_KEY_TYPES = {
    CONST.LCV.TEST_UNLOCKED0: FAKE_TEST_KEYS + FAKE_PROD_KEYS,
    CONST.LCV.DEV: FAKE_DEV_KEYS + FAKE_PROD_KEYS,
    CONST.LCV.PROD: FAKE_PROD_KEYS,
    CONST.LCV.PROD_END: FAKE_PROD_KEYS,
    CONST.LCV.RMA: FAKE_TEST_KEYS + FAKE_PROD_KEYS,
}

# Default OTP in TEST_UNLOCKED state
otp_json(
    name = "otp_json_default",
    partitions = [
        otp_partition(
            name = "OWNER_SW_CFG",
            items = {
                "OWNER_SW_CFG_ROM_BOOTSTRAP_EN": "0x739",
            },
        ),
        otp_partition(
            name = "CREATOR_SW_CFG",
            items = {
                "CREATOR_SW_CFG_ROM_EXEC_EN": "0xffffffff",
                # Enable use of entropy for countermeasures. See the definition
                # of `hardened_bool_t` in sw/device/lib/base/hardened.h.
                "CREATOR_SW_CFG_RNG_EN": "0x739",
                # Entropy source health check default values. This needs to be
                # populated when `CREATOR_SW_CFG_RNG_EN` is set to true.
                "CREATOR_SW_CFG_RNG_REPCNT_THRESHOLDS": "0xffffffff",
                "CREATOR_SW_CFG_RNG_REPCNTS_THRESHOLDS": "0xffffffff",
                "CREATOR_SW_CFG_RNG_ADAPTP_HI_THRESHOLDS": "0xffffffff",
                "CREATOR_SW_CFG_RNG_ADAPTP_LO_THRESHOLDS": "0x0",
                "CREATOR_SW_CFG_RNG_BUCKET_THRESHOLDS": "0xffffffff",
                "CREATOR_SW_CFG_RNG_MARKOV_HI_THRESHOLDS": "0xffffffff",
                "CREATOR_SW_CFG_RNG_MARKOV_LO_THRESHOLDS": "0x0",
                "CREATOR_SW_CFG_RNG_EXTHT_HI_THRESHOLDS": "0xffffffff",
                "CREATOR_SW_CFG_RNG_EXTHT_LO_THRESHOLDS": "0x0",
                "CREATOR_SW_CFG_RNG_ALERT_THRESHOLD": "0xfffd0002",
                "CREATOR_SW_CFG_RNG_HEALTH_CONFIG_DIGEST": "0x8264cf75",
            },
        ),
        otp_partition(
            name = "LIFE_CYCLE",
            count = 1,
            state = "TEST_UNLOCKED0",
        ),
    ],
)

otp_image(
    name = "otp_img_default",
    src = ":otp_json_default",
    visibility = ["//visibility:private"],
)

bitstream_splice(
    name = "bitstream_default_otp",
    src = "//hw/bitstream:rom",
    data = ":otp_img_default",
    meminfo = "//hw/bitstream:otp_mmi",
    tags = ["vivado"] + maybe_skip_in_ci(CONST.LCV.RMA),
    update_usr_access = True,
    visibility = ["//visibility:private"],
)

opentitan_functest(
    name = "rom_e2e_default_otp_bootup",
    srcs = ["empty_test.c"],
    cw310 = cw310_params(
        bitstream = ":bitstream_default_otp",
        tags = ["vivado"] + maybe_skip_in_ci(CONST.LCV.RMA),
    ),
    signed = True,
    targets = [
        "cw310_rom",
    ],
    deps = [
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:otp",
    ],
)

[opentitan_flash_binary(
    name = "empty_test_slot_{}".format(slot),
    srcs = ["empty_test.c"],
    devices = [
        "fpga_cw310",
        "sim_dv",
        "sim_verilator",
    ],
    signed = True,
    deps = [
        "//hw/ip/otp_ctrl/data:otp_ctrl_regs",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:lifecycle",
        "//sw/device/silicon_creator/lib/drivers:otp",
        "//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_{}".format(slot),
    ],
) for slot in SLOTS]

opentitan_functest(
    name = "rom_e2e_flash_ctrl_init",
    srcs = ["rom_e2e_flash_ctrl_init_test.c"],
    signed = True,
    targets = [
        "cw310_rom",
    ],
    deps = [
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:flash_ctrl",
        "//sw/device/silicon_creator/lib/drivers:otp",
    ],
)

opentitan_functest(
    name = "rom_e2e_shutdown_exception_c",
    srcs = ["rom_e2e_shutdown_exception_c_test.c"],
    cw310 = cw310_params(
        # Note: This test never prints a failure message so it will fail only
        # when it times out.
        exit_failure = "NO_FAILURE_MESSAGE",
        exit_success = MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.INTERRUPT.INSTRUCTION_ACCESS)),
    ),
    dv = dv_params(
        rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
    ),
    signed = True,
    targets = [
        "dv",
        "cw310_rom",
        "verilator",
    ],
    verilator = verilator_params(
        timeout = "eternal",
        exit_failure = "NO_FAILURE_MESSAGE",
        exit_success = MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.INTERRUPT.INSTRUCTION_ACCESS)),
        rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
    ),
    deps = [
        "//hw/top_earlgrey/sw/autogen:top_earlgrey",
        "//sw/device/silicon_creator/lib:manifest_def",
        "//sw/device/silicon_creator/lib/base:static_critical_boot_measurements",
        "//sw/device/silicon_creator/lib/base:static_critical_epmp_state",
        "//sw/device/silicon_creator/lib/base:static_critical_sec_mmio",
    ],
)

opentitan_functest(
    name = "rom_e2e_smoke",
    cw310 = cw310_params(
        bitstream = "//hw/bitstream:rom",
    ),
    dv = dv_params(
        rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
    ),
    key = FAKE_TEST_KEYS[0],
    ot_flash_binary = ":empty_test_slot_a",
    targets = [
        "cw310_rom",
        "verilator",
        "dv",
    ],
    verilator = verilator_params(
        timeout = "eternal",
        rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
    ),
)

opentitan_functest(
    name = "rom_e2e_static_critical",
    srcs = ["rom_e2e_static_critical_test.c"],
    dv = dv_params(
        rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
    ),
    signed = True,
    targets = [
        "dv",
        "cw310_rom",
        "verilator",
    ],
    verilator = verilator_params(
        timeout = "eternal",
        rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
    ),
    deps = [
        "//sw/device/lib/dif:hmac",
        "//sw/device/lib/testing:hmac_testutils",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/base:sec_mmio",
    ],
)

opentitan_flash_binary(
    name = "rom_e2e_keymgr_init_test",
    srcs = [":rom_e2e_keymgr_init_test.c"],
    deps = [
        "//sw/device/lib/dif:keymgr",
        "//sw/device/lib/testing:keymgr_testutils",
        "//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_a",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:otp",
    ],
)

rom_e2e_keymgr_init_configs = [
    {
        "name": "rom_ext_meas",
        "value": CONST.TRUE,
    },
    {
        "name": "rom_ext_no_meas",
        "value": CONST.FALSE,
    },
    {
        "name": "rom_ext_invalid_meas",
        "value": 0,
    },
]

[
    otp_json(
        name = "otp_json_keymgr_{}".format(config["name"]),
        partitions = [
            otp_partition(
                name = "OWNER_SW_CFG",
                items = {
                    "OWNER_SW_CFG_ROM_KEYMGR_ROM_EXT_MEAS_EN": "0x{}".format(hex_digits(config["value"])),
                },
            ),
        ],
    )
    for config in rom_e2e_keymgr_init_configs
]

[
    otp_image(
        name = "otp_img_keymgr_{}".format(config["name"]),
        src = "//hw/ip/otp_ctrl/data:otp_json_rma",
        overlays = STD_OTP_OVERLAYS + [":otp_json_keymgr_{}".format(config["name"])],
        visibility = ["//visibility:private"],
    )
    for config in rom_e2e_keymgr_init_configs
]

[
    bitstream_splice(
        name = "bitstream_keymgr_{}".format(config["name"]),
        src = "//hw/bitstream:rom",
        data = ":otp_img_keymgr_{}".format(config["name"]),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"],
        visibility = ["//visibility:private"],
    )
    for config in rom_e2e_keymgr_init_configs
]

[
    opentitan_functest(
        name = "rom_e2e_keymgr_init_{}".format(config["name"]),
        cw310 = cw310_params(
            bitstream = ":bitstream_keymgr_{}".format(config["name"]),
            tags = ["vivado"],
        ),
        dv = dv_params(
            otp = ":otp_img_keymgr_{}".format(config["name"]),
            rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
        ),
        ot_flash_binary = ":rom_e2e_keymgr_init_test",
        targets = [
            "cw310_rom",
            "dv",
            "verilator",
        ],
        verilator = verilator_params(
            timeout = "eternal",
            otp = ":otp_img_keymgr_{}".format(config["name"]),
            rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
        ),
    )
    for config in rom_e2e_keymgr_init_configs
]

test_suite(
    name = "keymgr_init",
    tags = ["manual"],
    tests = ["rom_e2e_keymgr_init_{}".format(
        config["name"],
    ) for config in rom_e2e_keymgr_init_configs],
)

opentitan_functest(
    name = "rom_e2e_c_init",
    srcs = ["rom_e2e_c_init_test.c"],
    cw310 = cw310_params(
        exit_failure = CONST.SHUTDOWN.PREFIX.BFV,
        exit_success = MSG_PASS,
    ),
    signed = True,
    targets = [
        "cw310_rom",
    ],
    deps = [
        "//hw/ip/uart/data:uart_regs",
        "//hw/top_earlgrey/ip/pinmux/data/autogen:pinmux_regs",
        "//hw/top_earlgrey/sw/autogen:top_earlgrey",
        "//sw/device/lib/runtime:hart",
        "//sw/device/lib/runtime:log",
        "//sw/device/lib/runtime:print",
        "//sw/device/silicon_creator/lib:manifest_def",
        "//sw/device/silicon_creator/lib/base:static_critical_boot_measurements",
        "//sw/device/silicon_creator/lib/base:static_critical_epmp_state",
        "//sw/device/silicon_creator/lib/base:static_critical_sec_mmio",
        "//sw/device/silicon_creator/lib/drivers:otp",
        "//sw/device/silicon_creator/lib/drivers:pinmux",
        "//sw/device/silicon_creator/lib/drivers:uart",
    ],
)

# Same as `:e2e_bootup_success`, but the Dev OTP image is spliced into the
# bitstream before it's sent to the CW310 FPGA.
opentitan_functest(
    name = "e2e_bootup_success_otp_dev",
    cw310 = cw310_params(
        bitstream = "//hw/bitstream:rom_otp_dev",
        # TODO(lowRISC/opentitan#13603): Remove this "manual" tag when the
        # bitstream target can fetch pre-spliced bitstream from GCP.
        tags = ["manual"],
    ),
    key = FAKE_TEST_KEYS[0],
    ot_flash_binary = ":empty_test_slot_a",
    targets = ["cw310_rom"],
)

[otp_image(
    name = "otp_img_e2e_bootstrap_entry_{}".format(lc_state.lower()),
    src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state.lower()),
    overlays = STD_OTP_OVERLAYS,
) for lc_state in structs.to_dict(CONST.LCV)]

# Splice OTP images into bitstreams
[
    bitstream_splice(
        name = "bitstream_e2e_bootstrap_entry_{}".format(lc_state.lower()),
        src = "//hw/bitstream:rom",
        data = ":otp_img_e2e_bootstrap_entry_{}".format(lc_state.lower()),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        update_usr_access = True,
    )
    for lc_state, lc_state_val in structs.to_dict(CONST.LCV).items()
]

[
    opentitan_functest(
        name = "e2e_bootstrap_entry_{}".format(lc_state.lower()),
        cw310 = cw310_params(
            bitstream = ":bitstream_e2e_bootstrap_entry_{}".format(lc_state.lower()),
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
            test_cmds = [
                "--rom-kind=rom",
                "--bitstream=\"$(location {bitstream})\"",
                "--bootstrap=\"$(location {flash})\"",
            ],
        ),
        ot_flash_binary = ":empty_test_slot_a",
        # We don't want the `empty_test` to run, but we _also_ don't want some
        # leftover flash image from a previous test to run.  So, bootstrap an
        # unsigned image to force a boot failure.
        signed = False,
        targets = ["cw310_rom"],
        test_harness = "//sw/host/tests/rom/e2e_bootstrap_entry",
        deps = [":bitstream_e2e_bootstrap_entry_{}".format(lc_state.lower())],
    )
    for lc_state, lc_state_val in structs.to_dict(CONST.LCV).items()
]

test_suite(
    name = "rom_e2e_bootstrap_entry",
    tags = ["manual"],
    tests = [":e2e_bootstrap_entry_{}".format(lc_state.lower()) for lc_state in structs.to_dict(CONST.LCV)],
)

otp_json(
    name = "otp_json_bootstrap_rma",
    partitions = [
        otp_partition(
            name = "CREATOR_SW_CFG",
            items = {
                "CREATOR_SW_CFG_RMA_SPIN_EN": hex(CONST.TRUE),
                "CREATOR_SW_CFG_RMA_SPIN_CYCLES": "10",
            },
        ),
        otp_partition(
            name = "SECRET2",
            items = {
                # This RMA token is a cSHAKE128 digest. The preimage is
                # hardcoded into the test harness [0] and the tool that
                # generated this token [1].
                #
                # [0]: //sw/host/tests/rom/e2e_bootstrap_rma
                # [1]: //sw/host/tests/rom/e2e_bootstrap_rma:gen_rma_token
                "RMA_TOKEN": "0x1faf9056acde66561685549803a28bec",
                "CREATOR_ROOT_KEY_SHARE0": "<random>",
                "CREATOR_ROOT_KEY_SHARE1": "<random>",
            },
            lock = True,
        ),
    ],
    visibility = ["//visibility:private"],
)

# This OTP image is tightly coupled with the "rom_bootstrap_rma" testpoint.
# Despite its name ending with "rma", it actually puts the device into the PROD
# lifecycle state in order to test the transition from PROD to RMA.
otp_image(
    name = "otp_img_bootstrap_rma",
    src = "//hw/ip/otp_ctrl/data:otp_json_prod",
    overlays = STD_OTP_OVERLAYS + [
        ":otp_json_bootstrap_rma",
    ],
    visibility = ["//visibility:private"],
)

bitstream_splice(
    name = "bitstream_bootstrap_rma",
    src = "//hw/bitstream:rom",
    data = ":otp_img_bootstrap_rma",
    meminfo = "//hw/bitstream:otp_mmi",
    tags = [
        "vivado",
    ],
    update_usr_access = True,
    visibility = ["//visibility:private"],
)

opentitan_functest(
    name = "e2e_bootstrap_rma",
    srcs = ["rom_e2e_bootstrap_rma_test.c"],
    cw310 = cw310_params(
        bitstream = ":bitstream_bootstrap_rma",
        tags = [
            "jtag",
            "vivado",
        ],
        test_cmds = [
            "--rom-kind=rom",
            "--bitstream=\"$(rootpath {bitstream})\"",
            "--bootstrap=\"$(rootpath {flash})\"",
            "--openocd=\"$(rootpath //third_party/openocd:openocd_bin)\"",
            "--openocd-adapter-config=\"$(rootpath //third_party/openocd:jtag_adapter_cfg)\"",
        ],
    ),
    data = [
        "//third_party/openocd:jtag_adapter_cfg",
        "//third_party/openocd:openocd_bin",
    ],
    key = LC_KEY_TYPES[CONST.LCV.PROD][0],
    targets = ["cw310_rom"],
    test_harness = "//sw/host/tests/rom/e2e_bootstrap_rma",
    deps = [
        "//hw/top_earlgrey/sw/autogen:top_earlgrey",
        "//sw/device/lib/base:macros",
        "//sw/device/lib/runtime:log",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:retention_sram",
    ],
)

opentitan_functest(
    name = "e2e_bootstrap_disabled",
    cw310 = cw310_params(
        bitstream = "//hw/bitstream:rom_otp_bootstrap_disabled",
        tags = [
            "vivado",
        ],
        test_cmds = [
            "--bitstream=\"$(location {bitstream})\"",
        ],
    ),
    # Since the bitstream disables bootstrap, there is no firmware to
    # load into the chip.  However, opentitan_functest wants to build a
    # binary target.  We'll build an unsigned do-nothing binary.
    ot_flash_binary = ":empty_test_slot_a",
    signed = False,
    targets = ["cw310_rom"],
    test_harness = "//sw/host/tests/rom/e2e_bootstrap_disabled",
)

[
    bitstream_splice(
        name = "bitstream_chip_specific_startup_{}".format(lc_state.lower()),
        src = "//hw/bitstream:rom",
        data = ":otp_img_e2e_bootstrap_entry_{}".format(lc_state.lower()),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        update_usr_access = True,
    )
    for lc_state, lc_state_val in get_lc_items()
]

[
    opentitan_functest(
        name = "e2e_chip_specific_startup_{}".format(lc_state.lower()),
        srcs = ["chip_specific_startup.c"],
        args = [],
        cw310 = cw310_params(
            bitstream = ":bitstream_chip_specific_startup_{}".format(lc_state.lower()),
            otp = ":otp_img_e2e_bootstrap_entry_{}".format(lc_state.lower()),
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
            test_cmds = [
                "--rom-kind=rom",
                "--bitstream=\"$(location //sw/device/silicon_creator/rom/e2e:bitstream_chip_specific_startup_{})\"".format(lc_state.lower()),
                "--bootstrap=\"$(location {flash})\"",
                "--otp-unprogrammed",
            ],
        ),
        signed = True,
        targets = ["cw310_rom"],
        test_harness = "//sw/host/tests/rom/e2e_chip_specific_startup",
        deps = [
            "//hw/ip/csrng/data:csrng_regs",
            "//hw/ip/edn/data:edn_regs",
            "//hw/ip/entropy_src/data:entropy_src_regs",
            "//hw/ip/otp_ctrl/data:otp_ctrl_regs",
            "//hw/top_earlgrey/ip/sensor_ctrl/data:sensor_ctrl_regs",
            "//hw/top_earlgrey/sw/autogen:top_earlgrey",
            "//sw/device/lib/base:mmio",
            "//sw/device/lib/dif:clkmgr",
            "//sw/device/lib/dif:lc_ctrl",
            "//sw/device/lib/dif:otp_ctrl",
            "//sw/device/lib/dif:sram_ctrl",
            "//sw/device/lib/runtime:log",
            "//sw/device/lib/testing/json:chip_specific_startup",
            "//sw/device/lib/testing/json:command",
            "//sw/device/lib/testing/test_framework:ottf_main",
            "//sw/device/lib/testing/test_framework:ujson_ottf",
            "//sw/device/lib/ujson",
        ],
    )
    for lc_state, lc_state_val in get_lc_items()
]

test_suite(
    name = "e2e_chip_specific_startup",
    tags = ["manual"],
    tests = [
        "e2e_chip_specific_startup_{}".format(lc_state)
        for lc_state, _ in get_lc_items()
    ],
)

opentitan_functest(
    name = "rom_ext_a_flash_a",
    cw310 = cw310_params(
        exit_failure = CONST.SHUTDOWN.PREFIX.BFV,
        exit_success = MSG_STARTING_ROM_EXT,
    ),
    ot_flash_binary = "//sw/device/silicon_creator/rom_ext:rom_ext_slot_a",
    targets = ["cw310_rom"],
)

opentitan_multislot_flash_binary(
    name = "rom_ext_b_flash_b_image",
    srcs = {
        "//sw/device/silicon_creator/rom_ext:rom_ext_slot_b": {
            "key": FAKE_TEST_KEYS[0],
            "offset": SLOTS["b"],
        },
    },
)

opentitan_functest(
    name = "rom_ext_b_flash_b",
    cw310 = cw310_params(
        exit_failure = CONST.SHUTDOWN.PREFIX.BFV,
        exit_success = MSG_STARTING_ROM_EXT,
    ),
    key = "multislot",
    ot_flash_binary = ":rom_ext_b_flash_b_image",
    targets = ["cw310_rom"],
)

opentitan_multislot_flash_binary(
    name = "rom_ext_a_flash_b_image",
    srcs = {
        "//sw/device/silicon_creator/rom_ext:rom_ext_slot_a": {
            "key": FAKE_TEST_KEYS[0],
            "offset": SLOTS["b"],
        },
    },
)

opentitan_functest(
    name = "rom_ext_a_flash_b",
    cw310 = cw310_params(
        exit_failure = MSG_STARTING_ROM_EXT,
        exit_success = MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.INTERRUPT.STORE_ACCESS)),
    ),
    key = "multislot",
    ot_flash_binary = ":rom_ext_a_flash_b_image",
    targets = ["cw310_rom"],
)

opentitan_multislot_flash_binary(
    name = "rom_ext_b_flash_a_image",
    srcs = {
        "//sw/device/silicon_creator/rom_ext:rom_ext_slot_b": {
            "key": FAKE_TEST_KEYS[0],
            "offset": SLOTS["a"],
        },
    },
)

opentitan_functest(
    name = "rom_ext_b_flash_a",
    cw310 = cw310_params(
        exit_failure = MSG_STARTING_ROM_EXT,
        exit_success = MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.INTERRUPT.STORE_ACCESS)),
    ),
    key = "multislot",
    ot_flash_binary = ":rom_ext_b_flash_a_image",
    targets = ["cw310_rom"],
)

opentitan_functest(
    name = "rom_ext_v_flash_a",
    cw310 = cw310_params(
        exit_failure = CONST.SHUTDOWN.PREFIX.BFV,
        exit_success = MSG_STARTING_ROM_EXT,
    ),
    ot_flash_binary = "//sw/device/silicon_creator/rom_ext:rom_ext_slot_virtual",
    targets = ["cw310_rom"],
)

opentitan_multislot_flash_binary(
    name = "rom_ext_v_flash_b_image",
    srcs = {
        "//sw/device/silicon_creator/rom_ext:rom_ext_slot_virtual": {
            "key": FAKE_TEST_KEYS[0],
            "offset": SLOTS["b"],
        },
    },
)

opentitan_functest(
    name = "rom_ext_v_flash_b",
    cw310 = cw310_params(
        exit_failure = CONST.SHUTDOWN.PREFIX.BFV,
        exit_success = MSG_STARTING_ROM_EXT,
    ),
    key = "multislot",
    ot_flash_binary = ":rom_ext_v_flash_b_image",
    targets = ["cw310_rom"],
)

opentitan_functest(
    name = "rom_ext_a_flash_a_bad_addr_trans",
    cw310 = cw310_params(
        exit_failure = MSG_STARTING_ROM_EXT,
        exit_success = MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.INTERRUPT.ILLEGAL_INSTRUCTION)),
    ),
    ot_flash_binary = "//sw/device/silicon_creator/rom_ext:rom_ext_slot_a_bad_address_translation",
    targets = ["cw310_rom"],
)

test_suite(
    name = "address_translation",
    tags = ["manual"],
    tests = [
        "rom_ext_a_flash_a",
        "rom_ext_a_flash_a_bad_addr_trans",
        "rom_ext_a_flash_b",
        "rom_ext_b_flash_a",
        "rom_ext_b_flash_b",
        "rom_ext_v_flash_a",
        "rom_ext_v_flash_b",
    ],
)

opentitan_functest(
    name = "sigverify_key_auth",
    cw310 = cw310_params(
        exit_failure = MSG_PASS,
        exit_success = MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.SIGVERIFY.BAD_KEY)),
    ),
    key = "unauthorized_0",
    ot_flash_binary = ":empty_test_slot_a",
    targets = ["cw310_rom"],
)

[otp_image(
    name = "otp_img_shutdown_output_{}".format(lc_state),
    src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state),
    overlays = STD_OTP_OVERLAYS,
) for lc_state, _ in get_lc_items()]

# Splice OTP images into bitstreams
[
    bitstream_splice(
        name = "bitstream_shutdown_output_{}".format(lc_state),
        src = "//hw/bitstream:rom",
        data = ":otp_img_shutdown_output_{}".format(lc_state),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"],
        update_usr_access = True,
    )
    for lc_state, _ in get_lc_items()
]

manifest({
    "name": "manifest_bad_identifier",
    "address_translation": hex(CONST.FALSE),
    "identifier": "0",
})

[opentitan_functest(
    name = "shutdown_output_{}".format(lc_state),
    cw310 = cw310_params(
        bitstream = ":bitstream_shutdown_output_{}".format(lc_state),
        exit_failure = MSG_PASS,
        exit_success = MSG_TEMPLATE_BFV_LCV.format(
            hex_digits(CONST.BFV.BOOT_POLICY.BAD_IDENTIFIER),
            hex_digits(lc_state_val),
        ),
        otp = ":otp_img_shutdown_output_{}".format(lc_state),
        tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
    ),
    dv = dv_params(
        otp = ":otp_img_shutdown_output_{}".format(lc_state),
        rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
    ),
    manifest = ":manifest_bad_identifier",
    ot_flash_binary = ":empty_test_slot_a",
    signed = False,
    targets = [
        "cw310_rom",
        "dv",
    ],
) for lc_state, lc_state_val in get_lc_items()]

test_suite(
    name = "shutdown_output",
    tags = ["manual"],
    tests = ["shutdown_output_{}".format(lc_state) for lc_state, _ in get_lc_items()],
)

SEC_VERS = [
    0,
    1,
    2,
]

[manifest({
    "name": "manifest_sec_ver_{}".format(sec_ver),
    "address_translation": hex(CONST.FALSE),
    "identifier": hex(CONST.ROM_EXT),
    "security_version": hex(sec_ver),
}) for sec_ver in SEC_VERS]

[opentitan_flash_binary(
    name = "empty_test_slot_{}_sec_ver_{}".format(slot, sec_ver),
    srcs = ["empty_test.c"],
    devices = ["fpga_cw310"],
    local_defines = [
        shell.quote("EMPTY_TEST_MSG=\"slot=%p, security_version=%01d, lc_state=0x%08x\", manifest_def_get(), manifest_def_get()->security_version, lifecycle_raw_state_get()"),
    ],
    manifest = ":manifest_sec_ver_{}".format(sec_ver),
    signed = True,
    deps = [
        "//hw/ip/otp_ctrl/data:otp_ctrl_regs",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:lifecycle",
        "//sw/device/silicon_creator/lib/drivers:otp",
        "//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_{}".format(slot),
    ],
) for slot in SLOTS for sec_ver in SEC_VERS]

[opentitan_multislot_flash_binary(
    name = "sec_ver_{}_{}_image".format(sec_ver_a, sec_ver_b),
    srcs = {
        ":empty_test_slot_a_sec_ver_{}".format(sec_ver_a): {
            "key": "fake_prod_key_0",
            "offset": SLOTS["a"],
        },
        ":empty_test_slot_b_sec_ver_{}".format(sec_ver_b): {
            "key": "fake_prod_key_0",
            "offset": SLOTS["b"],
        },
    },
    devices = ["fpga_cw310"],
) for sec_ver_a in SEC_VERS for sec_ver_b in SEC_VERS]

BOOT_POLICY_NEWER_CASES = [
    {
        "a": 0,
        "b": 0,
        "exit_success": "slot=0x20000000, security_version=0, lc_state=0x{}",
    },
    {
        "a": 0,
        "b": 1,
        "exit_success": "slot=0x20080000, security_version=1, lc_state=0x{}",
    },
    {
        "a": 1,
        "b": 0,
        "exit_success": "slot=0x20000000, security_version=1, lc_state=0x{}",
    },
    {
        "a": 1,
        "b": 1,
        "exit_success": "slot=0x20000000, security_version=1, lc_state=0x{}",
    },
]

[otp_image(
    name = "otp_img_boot_policy_newer_{}".format(lc_state.lower()),
    src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state.lower()),
    overlays = STD_OTP_OVERLAYS,
) for lc_state in structs.to_dict(CONST.LCV)]

# Splice OTP images into bitstreams
[
    bitstream_splice(
        name = "bitstream_boot_policy_newer_{}".format(lc_state.lower()),
        src = "//hw/bitstream:rom",
        data = ":otp_img_boot_policy_newer_{}".format(lc_state.lower()),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"],
        update_usr_access = True,
    )
    for lc_state in structs.to_dict(CONST.LCV)
]

[opentitan_functest(
    name = "boot_policy_newer_{}_a_{}_b_{}".format(
        lc_state.lower(),
        t["a"],
        t["b"],
    ),
    cw310 = cw310_params(
        bitstream = ":bitstream_boot_policy_newer_{}".format(lc_state.lower()),
        exit_success = t["exit_success"].format(hex_digits(lc_state_val)),
        tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
    ),
    key = "multislot",
    ot_flash_binary = ":sec_ver_{}_{}_image".format(
        t["a"],
        t["b"],
    ),
    targets = ["cw310_rom"],
) for lc_state, lc_state_val in structs.to_dict(CONST.LCV).items() for t in BOOT_POLICY_NEWER_CASES]

test_suite(
    name = "boot_policy_newer",
    tags = ["manual"],
    tests = ["boot_policy_newer_{}_a_{}_b_{}".format(
        lc_state.lower(),
        t["a"],
        t["b"],
    ) for lc_state in structs.to_dict(CONST.LCV) for t in BOOT_POLICY_NEWER_CASES],
)

BOOT_POLICY_ROLLBACK_CASES = [
    {
        "a": 0,
        "b": 0,
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.BOOT_POLICY.ROLLBACK)),
    },
    {
        "a": 0,
        "b": 1,
        "exit_success": "slot=0x20080000, security_version=1",
    },
    {
        "a": 2,
        "b": 0,
        "exit_success": "slot=0x20000000, security_version=2",
    },
    {
        "a": 1,
        "b": 1,
        "exit_success": "slot=0x20000000, security_version=1",
    },
]

otp_json(
    name = "otp_json_boot_policy_rollback",
    partitions = [
        otp_partition(
            name = "CREATOR_SW_CFG",
            items = {
                "CREATOR_SW_CFG_MIN_SEC_VER_ROM_EXT": "1",
            },
        ),
    ],
)

[otp_image(
    name = "otp_img_boot_policy_rollback_{}".format(lc_state),
    src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state),
    overlays = STD_OTP_OVERLAYS + [":otp_json_boot_policy_rollback"],
    visibility = ["//visibility:private"],
) for lc_state, _ in get_lc_items()]

[bitstream_splice(
    name = "bitstream_boot_policy_rollback_{}".format(
        lc_state,
    ),
    src = "//hw/bitstream:rom",
    data = ":otp_img_boot_policy_rollback_{}".format(
        lc_state,
    ),
    meminfo = "//hw/bitstream:otp_mmi",
    tags = ["vivado"],
    update_usr_access = True,
    visibility = ["//visibility:private"],
) for lc_state, _ in get_lc_items()]

[
    opentitan_functest(
        name = "boot_policy_rollback_{}_a_{}_b_{}".format(
            lc_state,
            t["a"],
            t["b"],
        ),
        cw310 = cw310_params(
            bitstream = "bitstream_boot_policy_rollback_{}".format(lc_state),
            exit_success = t["exit_success"],
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        ),
        key = "multislot",
        ot_flash_binary = ":sec_ver_{}_{}_image".format(
            t["a"],
            t["b"],
        ),
        targets = ["cw310_rom"],
    )
    for lc_state, lc_state_val in get_lc_items()
    for t in BOOT_POLICY_ROLLBACK_CASES
]

test_suite(
    name = "rom_e2e_boot_policy_rollback",
    tags = ["manual"],
    tests = [
        "boot_policy_rollback_{}_a_{}_b_{}".format(
            lc_state,
            t["a"],
            t["b"],
        )
        for lc_state, _ in get_lc_items()
        for t in BOOT_POLICY_ROLLBACK_CASES
    ],
)

# Watchdog configuration test cases.
#
# These test cases verify the ROM correctly configures the watchdog in each life
# cycle state. Tests are run for OTP configurations that disable the watchdog
# and for OTP configurations that enable the watchdog.

# Watchdog bite threshold for the watchdog-enabled cases. This is 2 seconds,
# assuming a 200kHz clock.
WATCHDOG_BITE_THRESHOLD = "0x61a80"

# OTP overlay that enables the watchdog. The bite threshold is 2 seconds,
# assuming a 200kHz clock.
otp_json(
    name = "otp_json_watchdog_enable",
    partitions = [
        otp_partition(
            name = "OWNER_SW_CFG",
            items = {"OWNER_SW_CFG_ROM_WATCHDOG_BITE_THRESHOLD_CYCLES": WATCHDOG_BITE_THRESHOLD},
        ),
    ],
)

# OTP images that enable the watchdog.
[otp_image(
    name = "otp_img_watchdog_enable_{}".format(lc_state.lower()),
    src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state.lower()),
    overlays = STD_OTP_OVERLAYS + [":otp_json_watchdog_enable"],
) for lc_state in structs.to_dict(CONST.LCV)]

# Bitstreams with the watchdog-enable OTP images spliced in.
[bitstream_splice(
    name = "bitstream_watchdog_enable_{}".format(lc_state.lower()),
    src = "//hw/bitstream:rom",
    data = ":otp_img_watchdog_enable_{}".format(lc_state.lower()),
    meminfo = "//hw/bitstream:otp_mmi",
    tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
    update_usr_access = True,
) for lc_state, lc_state_val in structs.to_dict(CONST.LCV).items()]

# Creates a binary that confirms the watchdog is enabled and a binary that
# confirms the watchdog is disabled.
[opentitan_flash_binary(
    name = "test_watchdog_{}".format(watchdog_config),
    srcs = ["watchdog_test.c"],
    devices = [
        "fpga_cw310",
        "sim_verilator",
    ],
    local_defines = [
        "EXPECT_WATCHDOG_{}".format(watchdog_config.upper()),
        "WATCHDOG_BITE_THRESHOLD={}".format(WATCHDOG_BITE_THRESHOLD),
    ],
    deps = [
        "//hw/ip/aon_timer/data:aon_timer_regs",
        "//hw/top_earlgrey/sw/autogen:top_earlgrey",
        "//sw/device/lib/base:abs_mmio",
        "//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_a",
        "//sw/device/lib/testing/test_framework:ottf_main",
    ],
) for watchdog_config in [
    "disabled",
    "enabled",
]]

WATCHDOG_TEST_CASES = {
    "disable": {
        "DEV": "disabled",
        "PROD": "disabled",
        "PROD_END": "disabled",
        "RMA": "disabled",
        "TEST_UNLOCKED0": "disabled",
    },
    "enable": {
        "DEV": "enabled",
        "PROD": "enabled",
        "PROD_END": "enabled",
        "RMA": "disabled",
        "TEST_UNLOCKED0": "disabled",
    },
}

# Bitstream targets (CW310) and otp images (verilator) for the watchdog config
# tests. The format argument should be replaced with the desired life cycle
# state.
WATCHDOG_BITSTREAM = {
    "disable": "//hw/bitstream:rom_otp_{}",
    "enable": ":bitstream_watchdog_enable_{}",
}

WATCHDOG_OTP = {
    "disable": "//hw/ip/otp_ctrl/data:img_{}",
    "enable": ":otp_img_watchdog_enable_{}",
}

[opentitan_functest(
    name = "watchdog_{}_{}".format(
        otp_config,
        lc_state.lower(),
    ),
    cw310 = cw310_params(
        bitstream = WATCHDOG_BITSTREAM[otp_config].format(lc_state.lower()),
        tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
    ),
    ot_flash_binary = ":test_watchdog_{}".format(WATCHDOG_TEST_CASES[otp_config][lc_state]),
    targets = [
        "cw310_rom",
        "verilator",
    ],
    verilator = verilator_params(
        timeout = "eternal",
        otp = WATCHDOG_OTP[otp_config].format(lc_state.lower()),
        rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
        # Test cases that enable the watchdog time out in verilator, cause
        # unknown.
        tags = ["broken"] if WATCHDOG_TEST_CASES[otp_config][lc_state] == "enabled" else [],
    ),
) for otp_config in [
    "disable",
    "enable",
] for lc_state, lc_state_val in structs.to_dict(CONST.LCV).items()]

test_suite(
    name = "rom_e2e_watchdog_reconfig",
    tags = ["manual"],
    tests = [
        "watchdog_{}_{}".format(
            otp_config,
            lc_state.lower(),
        )
        for otp_config in [
            "disable",
            "enable",
        ]
        for lc_state in structs.to_dict(CONST.LCV)
    ],
)

# Alert Handler configuration test cases.
#
# These test cases verify the ROM correctly configures the alert_handler in each
# life cycle state.

# Alert handler configuration is not checked in the TEST LC state.
ALERT_LC_STATES = get_lc_items(
    CONST.LCV.PROD,
    CONST.LCV.PROD_END,
    CONST.LCV.DEV,
    CONST.LCV.RMA,
)

[otp_image(
    name = "otp_img_alert_{}".format(lc_state),
    src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state),
    overlays = STD_OTP_OVERLAYS,
) for lc_state, _ in ALERT_LC_STATES]

[bitstream_splice(
    name = "bitstream_alert_{}".format(lc_state),
    src = "//hw/bitstream:rom",
    data = ":otp_img_alert_{}".format(lc_state),
    meminfo = "//hw/bitstream:otp_mmi",
    tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
    update_usr_access = True,
) for lc_state, lc_state_val in ALERT_LC_STATES]

[opentitan_flash_binary(
    name = "rom_e2e_alert_config_test_{}".format(lc_state),
    srcs = ["rom_e2e_alert_config_test.c"],
    devices = [
        "fpga_cw310",
    ],
    local_defines = [
        "OTP_ALERT_DIGEST=OTP_CTRL_PARAM_OWNER_SW_CFG_ROM_ALERT_DIGEST_{}_OFFSET".format(lc_state.upper()),
    ],
    deps = [
        "//hw/ip/otp_ctrl/data:otp_ctrl_regs",
        "//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_a",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:alert",
        "//sw/device/silicon_creator/lib/drivers:lifecycle",
        "//sw/device/silicon_creator/lib/drivers:otp",
    ],
) for lc_state, _ in ALERT_LC_STATES]

[
    opentitan_functest(
        name = "alert_{}".format(
            lc_state,
        ),
        cw310 = cw310_params(
            bitstream = ":bitstream_alert_{}".format(lc_state),
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        ),
        key = "fake_prod_key_0",
        ot_flash_binary = ":rom_e2e_alert_config_test_{}".format(lc_state),
        signed = True,
        targets = [
            "cw310_rom",
        ],
    )
    for lc_state, lc_state_val in ALERT_LC_STATES
]

test_suite(
    name = "rom_e2e_alert_config",
    tags = ["manual"],
    tests = [
        "alert_{}".format(lc_state)
        for lc_state, _ in ALERT_LC_STATES
    ],
)

otp_json(
    name = "shutdown_alert_owner_sw_cfg",
    partitions = [
        otp_partition(
            name = "OWNER_SW_CFG",
            items = {
                # Enable bootstrap.
                "OWNER_SW_CFG_ROM_BOOTSTRAP_EN": hex(CONST.TRUE),
                # Report errors without any redaction.
                "OWNER_SW_CFG_ROM_ERROR_REPORTING": hex(CONST.SHUTDOWN.REDACT.NONE),
                # Enable class A alerts.
                "OWNER_SW_CFG_ROM_ALERT_CLASS_EN": hex(
                    CONST.ALERT.NONE << 24 |
                    CONST.ALERT.NONE << 16 |
                    CONST.ALERT.NONE << 8 |
                    CONST.ALERT.ENABLE,
                ),
                # Configure class A to escalate until phase 3 and disable other classes.
                "OWNER_SW_CFG_ROM_ALERT_ESCALATION": hex(
                    CONST.ALERT.ESC_NONE << 24 |
                    CONST.ALERT.ESC_NONE << 16 |
                    CONST.ALERT.ESC_NONE << 8 |
                    CONST.ALERT.ESC_PHASE_3,
                ),
                # Classify UART0 alerts (alert source 0) as class A and leave others as unconfigured.
                "OWNER_SW_CFG_ROM_ALERT_CLASSIFICATION": [
                    hex(
                        CONST.ALERT.CLASS_A << 24 |
                        CONST.ALERT.CLASS_A << 16 |
                        CONST.ALERT.CLASS_A << 8 |
                        CONST.ALERT.CLASS_A,
                    ),
                ] + [
                    hex(
                        CONST.ALERT.CLASS_X << 24 |
                        CONST.ALERT.CLASS_X << 16 |
                        CONST.ALERT.CLASS_X << 8 |
                        CONST.ALERT.CLASS_X,
                    ),
                ] * 79,
                # Leave local alert classification as unconfigured.
                "OWNER_SW_CFG_ROM_LOCAL_ALERT_CLASSIFICATION": [hex(
                    CONST.ALERT.CLASS_X << 24 |
                    CONST.ALERT.CLASS_X << 16 |
                    CONST.ALERT.CLASS_X << 8 |
                    CONST.ALERT.CLASS_X,
                )] * 16,
                # Set the alert accumulation thresholds to 0.
                "OWNER_SW_CFG_ROM_ALERT_ACCUM_THRESH": ["0x00000000"] * 4,
                # Set the alert timeout cycles to 0.
                "OWNER_SW_CFG_ROM_ALERT_TIMEOUT_CYCLES": ["0x00000000"] * 4,
                # Set the alert phase cycles to 0.
                "OWNER_SW_CFG_ROM_ALERT_PHASE_CYCLES": ["0x00000000"] * 16,
            },
        ),
    ],
)

otp_alert_digest(
    name = "shutdown_alert_digest_cfg",
    otp_img = ":shutdown_alert_owner_sw_cfg",
)

[otp_image(
    name = "otp_img_shutdown_alert_{}".format(lc_state),
    src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state),
    overlays = STD_OTP_OVERLAYS + [
        ":shutdown_alert_owner_sw_cfg",
        ":shutdown_alert_digest_cfg",
    ],
) for lc_state, _ in ALERT_LC_STATES]

[bitstream_splice(
    name = "bitstream_shutdown_alert_{}".format(lc_state),
    src = "//hw/bitstream:rom",
    data = ":otp_img_shutdown_alert_{}".format(lc_state),
    meminfo = "//hw/bitstream:otp_mmi",
    tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
    update_usr_access = True,
) for lc_state, lc_state_val in ALERT_LC_STATES]

[opentitan_flash_binary(
    name = "rom_e2e_shutdown_alert_config_test_{}".format(lc_state),
    srcs = ["rom_e2e_shutdown_alert_config_test.c"],
    devices = [
        "fpga_cw310",
    ],
    deps = [
        "//hw/ip/uart/data:uart_regs",
        "//sw/device/lib/base:abs_mmio",
        "//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_a",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:retention_sram",
        "//sw/device/silicon_creator/lib/drivers:rstmgr",
    ],
) for lc_state, _ in ALERT_LC_STATES]

[
    opentitan_functest(
        name = "shutdown_alert_{}".format(lc_state),
        cw310 = cw310_params(
            bitstream = ":bitstream_shutdown_alert_{}".format(lc_state),
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        ),
        key = "fake_prod_key_0",
        ot_flash_binary = ":rom_e2e_shutdown_alert_config_test_{}".format(lc_state),
        signed = True,
        targets = [
            "cw310_rom",
        ],
    )
    for lc_state, lc_state_val in ALERT_LC_STATES
]

test_suite(
    name = "rom_e2e_shutdown_alert_config",
    tags = ["manual"],
    tests = [
        "shutdown_alert_{}".format(lc_state)
        for lc_state, _ in ALERT_LC_STATES
    ],
)

SIGVERIFY_MOD_EXP_CASES = [
    {
        "name": "sw",
        "use_sw_rsa_verify": CONST.TRUE,
        "exit_success": {lc_state: "use_sw_rsa_verify=0x00000739" for lc_state, _ in get_lc_items()},
    },
    {
        "name": "otbn",
        "use_sw_rsa_verify": CONST.FALSE,
        "exit_success": {lc_state: "use_sw_rsa_verify=0x000001d4" for lc_state, _ in get_lc_items()},
    },
    {
        "name": "invalid",
        "use_sw_rsa_verify": 0,
        "exit_success": {
            lc_state: MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.INTERRUPT.ILLEGAL_INSTRUCTION)) if lc_state_val != CONST.LCV.TEST_UNLOCKED0 else "use_sw_rsa_verify=0x00000000"
            for lc_state, lc_state_val in get_lc_items()
        },
    },
]

opentitan_flash_binary(
    name = "empty_test_sigverify_mod_exp",
    srcs = ["empty_test.c"],
    devices = [
        "fpga_cw310",
        "sim_dv",
    ],
    local_defines = [
        shell.quote("EMPTY_TEST_MSG=\"use_sw_rsa_verify=0x%08x\", otp_read32(OTP_CTRL_PARAM_CREATOR_SW_CFG_SIGVERIFY_RSA_MOD_EXP_IBEX_EN_OFFSET)"),
    ],
    signed = True,
    deps = [
        "//hw/ip/otp_ctrl/data:otp_ctrl_regs",
        "//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_a",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:lifecycle",
        "//sw/device/silicon_creator/lib/drivers:otp",
    ],
)

[
    otp_json(
        name = "otp_json_sigverify_mod_exp_{}".format(t["name"]),
        partitions = [
            otp_partition(
                name = "CREATOR_SW_CFG",
                items = {"CREATOR_SW_CFG_SIGVERIFY_RSA_MOD_EXP_IBEX_EN": hex(t["use_sw_rsa_verify"])},
            ),
        ],
    )
    for t in SIGVERIFY_MOD_EXP_CASES
]

[
    otp_image(
        name = "otp_img_sigverify_mod_exp_{}_{}".format(
            lc_state,
            t["name"],
        ),
        src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state),
        overlays = STD_OTP_OVERLAYS + [":otp_json_sigverify_mod_exp_{}".format(t["name"])],
        visibility = ["//visibility:private"],
    )
    for lc_state, _ in get_lc_items()
    for t in SIGVERIFY_MOD_EXP_CASES
]

[
    bitstream_splice(
        name = "bitstream_sigverify_mod_exp_{}_{}".format(
            lc_state,
            t["name"],
        ),
        src = "//hw/bitstream:rom",
        data = ":otp_img_sigverify_mod_exp_{}_{}".format(
            lc_state,
            t["name"],
        ),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"],
        update_usr_access = True,
        visibility = ["//visibility:private"],
    )
    for lc_state, _ in get_lc_items()
    for t in SIGVERIFY_MOD_EXP_CASES
]

[
    opentitan_functest(
        name = "sigverify_mod_exp_{}_{}".format(
            lc_state,
            t["name"],
        ),
        cw310 = cw310_params(
            bitstream = ":bitstream_sigverify_mod_exp_{}_{}".format(
                lc_state,
                t["name"],
            ),
            exit_success = t["exit_success"][lc_state],
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        ),
        ot_flash_binary = ":empty_test_sigverify_mod_exp",
        targets = ["cw310_rom"],
    )
    for lc_state, lc_state_val in get_lc_items()
    for t in SIGVERIFY_MOD_EXP_CASES
]

test_suite(
    name = "rom_e2e_sigverify_mod_exp",
    tags = ["manual"],
    tests = [
        "sigverify_mod_exp_{}_{}".format(
            lc_state,
            t["name"],
        )
        for lc_state, _ in get_lc_items()
        for t in SIGVERIFY_MOD_EXP_CASES
    ],
)

BOOT_POLICY_BAD_MANIFEST_CASES = [
    {
        "name": "bad_identifier",
        "manifest": {
            "identifier": "0",
        },
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.BOOT_POLICY.BAD_IDENTIFIER)),
    },
    {
        "name": "too_small",
        "manifest": {
            "identifier": hex(CONST.ROM_EXT),
            "length": hex(CONST.ROM_EXT_SIZE_MIN - 1),
        },
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.BOOT_POLICY.BAD_LENGTH)),
    },
    {
        "name": "too_large",
        "manifest": {
            "identifier": hex(CONST.ROM_EXT),
            "length": hex(CONST.ROM_EXT_SIZE_MAX + 1),
        },
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.BOOT_POLICY.BAD_LENGTH)),
    },
    {
        "name": "empty_code",
        "manifest": {
            # Note: `length` is filled automatically unless overriden here.
            "identifier": hex(CONST.ROM_EXT),
            "code_start": hex(CONST.MANIFEST_SIZE + 12),
            "code_end": hex(CONST.MANIFEST_SIZE + 12),
        },
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.MANIFEST.BAD_CODE_REGION)),
    },
    {
        "name": "code_in_manifest",
        "manifest": {
            "identifier": hex(CONST.ROM_EXT),
            "code_start": hex(CONST.MANIFEST_SIZE - 4),
            "code_end": hex(CONST.MANIFEST_SIZE + 12),
            "entry_point": hex(CONST.MANIFEST_SIZE + 8),
        },
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.MANIFEST.BAD_CODE_REGION)),
    },
    {
        "name": "code_outside_image",
        "manifest": {
            "identifier": hex(CONST.ROM_EXT),
            "code_start": hex(CONST.ROM_EXT_SIZE_MAX),
            "code_end": hex(CONST.MANIFEST_SIZE + 12),
            "entry_point": hex(CONST.MANIFEST_SIZE + 8),
        },
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.MANIFEST.BAD_CODE_REGION)),
    },
    {
        "name": "code_start_unaligned",
        "manifest": {
            "identifier": hex(CONST.ROM_EXT),
            "code_start": hex(CONST.MANIFEST_SIZE + 6),
            "code_end": hex(CONST.MANIFEST_SIZE + 12),
            "entry_point": hex(CONST.MANIFEST_SIZE + 8),
        },
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.MANIFEST.BAD_CODE_REGION)),
    },
    {
        "name": "code_end_unaligned",
        "manifest": {
            "identifier": hex(CONST.ROM_EXT),
            "code_start": hex(CONST.MANIFEST_SIZE + 8),
            "code_end": hex(CONST.MANIFEST_SIZE + 10),
            "entry_point": hex(CONST.MANIFEST_SIZE + 8),
        },
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.MANIFEST.BAD_CODE_REGION)),
    },
    {
        "name": "entry_before_code_start",
        "manifest": {
            "identifier": hex(CONST.ROM_EXT),
            "code_start": hex(CONST.MANIFEST_SIZE + 8),
            "code_end": hex(CONST.MANIFEST_SIZE + 12),
            "entry_point": hex(CONST.MANIFEST_SIZE + 4),
        },
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.MANIFEST.BAD_ENTRY_POINT)),
    },
    {
        "name": "entry_at_code_end",
        "manifest": {
            "identifier": hex(CONST.ROM_EXT),
            "code_start": hex(CONST.MANIFEST_SIZE + 8),
            "code_end": hex(CONST.MANIFEST_SIZE + 12),
            "entry_point": hex(CONST.MANIFEST_SIZE + 12),
        },
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.MANIFEST.BAD_ENTRY_POINT)),
    },
    {
        "name": "entry_unaligned",
        "manifest": {
            "identifier": hex(CONST.ROM_EXT),
            "code_start": hex(CONST.MANIFEST_SIZE + 8),
            "code_end": hex(CONST.MANIFEST_SIZE + 12),
            "entry_point": hex(CONST.MANIFEST_SIZE + 10),
        },
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.MANIFEST.BAD_ENTRY_POINT)),
    },
    {
        "name": "rollback",
        "manifest": {
            "identifier": hex(CONST.ROM_EXT),
            "code_start": hex(CONST.MANIFEST_SIZE + 8),
            "code_end": hex(CONST.MANIFEST_SIZE + 12),
            "entry_point": hex(CONST.MANIFEST_SIZE + 8),
            "security_version": "0",
        },
        "exit_success": MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.BOOT_POLICY.ROLLBACK)),
        "sec_ver": 1,
    },
]

[opentitan_flash_binary(
    name = "boot_policy_bad_manifest_{}_{}_bin".format(
        t["name"],
        slot,
    ),
    srcs = ["empty_test.c"],
    devices = [
        "fpga_cw310",
        "sim_dv",
        "sim_verilator",
    ],
    manifest = manifest(dict(
        t["manifest"],
        name = "{}_{}".format(
            t["name"],
            slot,
        ),
    )),
    signed = True,
    deps = [
        "//hw/ip/otp_ctrl/data:otp_ctrl_regs",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:lifecycle",
        "//sw/device/silicon_creator/lib/drivers:otp",
        "//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_{}".format(slot),
    ],
) for t in BOOT_POLICY_BAD_MANIFEST_CASES for slot in SLOTS]

[opentitan_multislot_flash_binary(
    name = "boot_policy_bad_manifest_{}_{}_img".format(
        t["name"],
        slot,
    ),
    srcs = {
        "boot_policy_bad_manifest_{}_{}_bin".format(
            t["name"],
            slot,
        ): {
            "key": FAKE_TEST_KEYS[0],
            "offset": offset,
        },
    },
    devices = [
        "fpga_cw310",
        "sim_dv",
        "sim_verilator",
    ],
) for t in BOOT_POLICY_BAD_MANIFEST_CASES for slot, offset in SLOTS.items()]

[
    otp_json(
        name = "otp_json_sec_ver_{}".format(sec_ver),
        partitions = [
            otp_partition(
                name = "CREATOR_SW_CFG",
                items = {
                    "CREATOR_SW_CFG_MIN_SEC_VER_ROM_EXT": "{}".format(sec_ver),
                },
            ),
        ],
    )
    for sec_ver in [
        0,
        1,
    ]
]

[
    otp_image(
        name = "otp_img_boot_policy_bad_manifest_{}_sec_ver_{}".format(
            lc_state,
            sec_ver,
        ),
        src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state),
        overlays = STD_OTP_OVERLAYS + [":otp_json_sec_ver_{}".format(sec_ver)],
        visibility = ["//visibility:private"],
    )
    for lc_state, _ in get_lc_items()
    for sec_ver in [
        0,
        1,
    ]
]

[
    bitstream_splice(
        name = "bitstream_boot_policy_bad_manifest_{}_sec_ver_{}".format(
            lc_state,
            sec_ver,
        ),
        src = "//hw/bitstream:rom",
        data = ":otp_img_boot_policy_bad_manifest_{}_sec_ver_{}".format(
            lc_state,
            sec_ver,
        ),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"],
        update_usr_access = True,
        visibility = ["//visibility:private"],
    )
    for lc_state, _ in get_lc_items()
    for sec_ver in [
        0,
        1,
    ]
]

[
    opentitan_functest(
        name = "boot_policy_bad_manifest_{}_{}_{}".format(
            lc_state,
            t["name"],
            slot,
        ),
        cw310 = cw310_params(
            bitstream = "bitstream_boot_policy_bad_manifest_{}_sec_ver_{}".format(
                lc_state,
                t.get("sec_ver", 0),
            ),
            exit_success = t["exit_success"],
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        ),
        key = "multislot",
        ot_flash_binary = "boot_policy_bad_manifest_{}_{}_img".format(
            t["name"],
            slot,
        ),
        targets = [
            "cw310_rom",
            "verilator",
        ],
        verilator = verilator_params(
            tags = [
                # FIXME:#16056 Verilator fails to set up test.
                "vivado",
                "broken",
            ],
        ),
    )
    for lc_state, lc_state_val in get_lc_items()
    for t in BOOT_POLICY_BAD_MANIFEST_CASES
    for slot in SLOTS
]

test_suite(
    name = "rom_e2e_boot_policy_bad_manifest",
    tags = ["manual"],
    tests = [
        "boot_policy_bad_manifest_{}_{}_{}".format(
            lc_state,
            t["name"],
            slot,
        )
        for lc_state, _ in get_lc_items()
        for t in BOOT_POLICY_BAD_MANIFEST_CASES
        for slot in SLOTS
    ],
)

BOOT_DATA_RECOVERY_CASES = [
    {
        "lc_state": "test_unlocked0",
        "min_sec_ver": 0,
        "default_boot_data": "nodefault",
        "expected_bfv": None,
    },
    {
        "lc_state": "dev",
        "min_sec_ver": 1,
        "default_boot_data": "nodefault",
        "expected_bfv": None,
    },
    {
        "lc_state": "prod",
        "min_sec_ver": 1,
        "default_boot_data": "default",
        "expected_bfv": None,
    },
    {
        "lc_state": "prod",
        "min_sec_ver": 0,
        "default_boot_data": "nodefault",
        "expected_bfv": CONST.BFV.BOOT_DATA.NOT_FOUND,
    },
    {
        "lc_state": "prod_end",
        "min_sec_ver": 0,
        "default_boot_data": "default",
        "expected_bfv": None,
    },
    {
        "lc_state": "prod_end",
        "min_sec_ver": 1,
        "default_boot_data": "nodefault",
        "expected_bfv": CONST.BFV.BOOT_DATA.NOT_FOUND,
    },
    {
        "lc_state": "rma",
        "min_sec_ver": 0,
        "default_boot_data": "nodefault",
        "expected_bfv": None,
    },
]

[otp_json(
    name = "boot_data_recovery_creator_sw_cfg_{}_{}".format(
        case["lc_state"],
        case["default_boot_data"],
    ),
    partitions = [
        otp_partition(
            name = "CREATOR_SW_CFG",
            items = {
                # Set the min_sec version.
                "CREATOR_SW_CFG_MIN_SEC_VER_ROM_EXT": hex(case["min_sec_ver"]),
                # Set allowing use of default boot data in PROD LC state.
                "CREATOR_SW_CFG_DEFAULT_BOOT_DATA_IN_PROD_EN": hex(
                    CONST.TRUE if case["default_boot_data"] == "default" else CONST.FALSE,
                ),
            },
        ),
    ],
) for case in BOOT_DATA_RECOVERY_CASES]

[otp_image(
    name = "otp_img_boot_data_recovery_{}_{}".format(
        case["lc_state"],
        case["default_boot_data"],
    ),
    src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(case["lc_state"]),
    overlays = STD_OTP_OVERLAYS + [":boot_data_recovery_creator_sw_cfg_{}_{}".format(
        case["lc_state"],
        case["default_boot_data"],
    )],
) for case in BOOT_DATA_RECOVERY_CASES]

[bitstream_splice(
    name = "bitstream_boot_data_recovery_{}_{}".format(
        case["lc_state"],
        case["default_boot_data"],
    ),
    src = "//hw/bitstream:rom",
    data = ":otp_img_boot_data_recovery_{}_{}".format(
        case["lc_state"],
        case["default_boot_data"],
    ),
    meminfo = "//hw/bitstream:otp_mmi",
    tags = ["vivado"] + maybe_skip_in_ci(getattr(
        CONST.LCV,
        case["lc_state"].upper(),
    )),
    update_usr_access = True,
) for case in BOOT_DATA_RECOVERY_CASES]

[opentitan_flash_binary(
    name = "rom_e2e_boot_data_recovery_{}_{}".format(
        case["lc_state"],
        case["default_boot_data"],
    ),
    srcs = ["empty_test.c"],
    devices = [
        "fpga_cw310",
    ],
    manifest = manifest(
        dict(
            name = "boot_data_recovery_manifest_{}_{}".format(
                case["lc_state"],
                case["default_boot_data"],
            ),
            address_translation = hex(CONST.FALSE),
            identifier = hex(CONST.ROM_EXT),
            security_version = hex(2),
        ),
    ),
    deps = [
        "//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_a",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:otp",
    ],
) for case in BOOT_DATA_RECOVERY_CASES]

[
    opentitan_functest(
        name = "boot_data_recovery_{}_{}".format(
            case["lc_state"],
            case["default_boot_data"],
        ),
        cw310 = cw310_params(
            bitstream = ":bitstream_boot_data_recovery_{}_{}".format(
                case["lc_state"],
                case["default_boot_data"],
            ),
            exit_success = MSG_TEMPLATE_BFV.format(hex_digits(case["expected_bfv"])) if case["expected_bfv"] != None else MSG_PASS,
            tags = ["vivado"] + maybe_skip_in_ci(getattr(
                CONST.LCV,
                case["lc_state"].upper(),
            )),
        ),
        key = "fake_prod_key_0",
        ot_flash_binary = ":rom_e2e_boot_data_recovery_{}_{}".format(
            case["lc_state"],
            case["default_boot_data"],
        ),
        signed = True,
        targets = [
            "cw310_rom",
        ],
    )
    for case in BOOT_DATA_RECOVERY_CASES
]

test_suite(
    name = "rom_e2e_boot_data_recovery",
    tags = ["manual"],
    tests = [
        "boot_data_recovery_{}_{}".format(
            case["lc_state"],
            case["default_boot_data"],
        )
        for case in BOOT_DATA_RECOVERY_CASES
    ],
)

SHUTDOWN_WATCHDOG_BITE_THRESHOLDS = [
    400000,  # 2 seconds at 200 kHz
    0,  # Watchdog disabled
]

SHUTDOWN_WATCHDOG_CASES = [
    {
        "lc_state": lc_state,
        "exit_success": "Returning after 1 seconds",
        "bite_threshold": bite_threshold,
    }
    for lc_state in [
        "test_unlocked0",
        "rma",
    ]
    for bite_threshold in SHUTDOWN_WATCHDOG_BITE_THRESHOLDS
] + [
    {
        "lc_state": lc_state,
        "exit_success": "Returning after 1 seconds" if bite_threshold == 0 else "I00000[^\r\n]*\r\nROM:[0-9a-f]{8}\r\n",
        "bite_threshold": bite_threshold,
    }
    for lc_state in [
        "dev",
        "prod",
        "prod_end",
    ]
    for bite_threshold in SHUTDOWN_WATCHDOG_BITE_THRESHOLDS
]

[
    otp_json(
        name = "otp_json_shutdown_watchdog_{}_{}".format(
            t["lc_state"],
            t["bite_threshold"],
        ),
        partitions = [
            otp_partition(
                name = "OWNER_SW_CFG",
                items = {"OWNER_SW_CFG_ROM_WATCHDOG_BITE_THRESHOLD_CYCLES": hex(t["bite_threshold"])},
            ),
        ],
    )
    for t in SHUTDOWN_WATCHDOG_CASES
]

[
    otp_image(
        name = "otp_img_shutdown_watchdog_{}_{}".format(
            t["lc_state"],
            t["bite_threshold"],
        ),
        src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(t["lc_state"]),
        overlays = STD_OTP_OVERLAYS + [
            ":otp_json_shutdown_watchdog_{}_{}".format(
                t["lc_state"],
                t["bite_threshold"],
            ),
        ],
    )
    for t in SHUTDOWN_WATCHDOG_CASES
]

[
    bitstream_splice(
        name = "bitstream_shutdown_watchdog_{}_{}".format(
            t["lc_state"],
            t["bite_threshold"],
        ),
        src = "//hw/bitstream:rom",
        data = ":otp_img_shutdown_watchdog_{}_{}".format(
            t["lc_state"],
            t["bite_threshold"],
        ),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"],
        update_usr_access = True,
        visibility = ["//visibility:private"],
    )
    for t in SHUTDOWN_WATCHDOG_CASES
]

[
    opentitan_functest(
        name = "shutdown_watchdog_{}_{}".format(
            t["lc_state"],
            t["bite_threshold"],
        ),
        srcs = ["hang_test.c"],
        cw310 = cw310_params(
            bitstream = ":bitstream_shutdown_watchdog_{}_{}".format(
                t["lc_state"],
                t["bite_threshold"],
            ),
            exit_success = t["exit_success"],
            tags = ["vivado"] + maybe_skip_in_ci(getattr(
                CONST.LCV,
                t["lc_state"].upper(),
            )),
        ),
        local_defines = [
            "HANG_SECS=1",
        ],
        targets = ["cw310_rom"],
        deps = [
            "//sw/device/lib/testing/test_framework:ottf_main",
        ],
    )
    for t in SHUTDOWN_WATCHDOG_CASES
]

test_suite(
    name = "rom_e2e_shutdown_watchdog",
    tags = ["manual"],
    tests = [
        "shutdown_watchdog_{}_{}".format(
            t["lc_state"],
            t["bite_threshold"],
        )
        for t in SHUTDOWN_WATCHDOG_CASES
    ],
)

# list of keys that will be used to build various flash images
# it must contain at least one key of each type and contains all
# the keys used in SIGVERIFY_LCS_2_VALID_KEY
SIGVERIFY_LC_KEYS = [
    FAKE_TEST_KEYS[0],
    FAKE_DEV_KEYS[0],
    FAKE_PROD_KEYS[0],
]

# provide a valid key for each LC state
# this key must be present in SIGVERIFY_LC_KEYS to ensure
# that the proper flush images are built
SIGVERIFY_LCS_2_VALID_KEY = {
    "test_unlocked0": FAKE_TEST_KEYS[0],
    "dev": FAKE_DEV_KEYS[0],
    "prod": FAKE_PROD_KEYS[0],
    "prod_end": FAKE_PROD_KEYS[0],
    "rma": FAKE_PROD_KEYS[0],
}

[
    genrule(
        name = "empty_test_slot_{}_corrupted_{}_bin_signed_{}".format(slot, device, key),
        testonly = True,
        srcs = ["empty_test_slot_{}_{}_bin_signed_{}".format(slot, device, key)],
        outs = ["empty_test_slot_{}_corrupted_{}.{}.signed.bin".format(slot, device, key)],
        cmd_bash = "cat $(SRCS) > $(OUTS) && dd if=/dev/zero of=$(OUTS) bs=4 seek=7 count=1 conv=notrunc status=none".format(slot),
    )
    for slot in SLOTS
    for device in [
        "sim_dv",
        "fpga_cw310",
    ]
    for key in SIGVERIFY_LC_KEYS
]

# The below three rule sets (bin_to_vmem, scramble_flash_vmem, and filegroup)
# are needed to run `sigverify_always` test in DV.
[
    bin_to_vmem(
        name = "empty_test_slot_{}_corrupted_sim_dv_vmem64_signed_{}".format(slot, key),
        testonly = True,
        bin = "empty_test_slot_{}_corrupted_sim_dv_bin_signed_{}".format(slot, key),
        word_size = 64,  # Backdoor-load VMEM image uses 64-bit words
    )
    for slot in SLOTS
    for key in SIGVERIFY_LC_KEYS
]

[
    scramble_flash_vmem(
        name = "empty_test_slot_{}_corrupted_sim_dv_scr_vmem64_signed_{}".format(slot, key),
        testonly = True,
        vmem = "empty_test_slot_{}_corrupted_sim_dv_vmem64_signed_{}".format(slot, key),
    )
    for slot in SLOTS
    for key in SIGVERIFY_LC_KEYS
]

[
    filegroup(
        name = "empty_test_slot_{}_corrupted_sim_dv".format(slot),
        testonly = True,
        srcs = [
            "empty_test_slot_{}_corrupted_sim_dv_{}_signed_{}".format(slot, file_type, key)
            for file_type in [
                "bin",
                "vmem64",
                "scr_vmem64",
            ]
            for key in SIGVERIFY_LC_KEYS
        ],
    )
    for slot in SLOTS
]

BOOT_POLICY_VALID_CASES = [
    {
        "desc": "good",
        "suffix": "",
    },
    {
        "desc": "bad",
        "suffix": "_corrupted",
    },
]

[
    opentitan_multislot_flash_binary(
        name = "boot_policy_valid_img_a_{}_b_{}".format(
            a["desc"],
            b["desc"],
        ),
        srcs = {
            ":empty_test_slot_a{}".format(a["suffix"]): {
                "key": "fake_prod_key_0",
                "offset": SLOTS["a"],
            },
            ":empty_test_slot_b{}".format(b["suffix"]): {
                "key": "fake_prod_key_0",
                "offset": SLOTS["b"],
            },
        },
        devices = ["fpga_cw310"],
    )
    for a in BOOT_POLICY_VALID_CASES
    for b in BOOT_POLICY_VALID_CASES
]

[
    otp_image(
        name = "otp_img_boot_policy_valid_{}".format(lc_state.lower()),
        src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state.lower()),
        overlays = STD_OTP_OVERLAYS,
    )
    for lc_state in structs.to_dict(CONST.LCV)
]

# Splice OTP images into bitstreams
[
    bitstream_splice(
        name = "bitstream_boot_policy_valid_{}".format(lc_state.lower()),
        src = "//hw/bitstream:rom",
        data = ":otp_img_boot_policy_valid_{}".format(lc_state.lower()),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"],
        update_usr_access = True,
    )
    for lc_state in structs.to_dict(CONST.LCV)
]

[
    opentitan_functest(
        name = "boot_policy_valid_{}_a_{}_b_{}".format(
            lc_state,
            a["desc"],
            b["desc"],
        ),
        cw310 = cw310_params(
            bitstream = "bitstream_boot_policy_valid_{}".format(lc_state),
            exit_failure = MSG_PASS if a["desc"] == b["desc"] and a["desc"] == "bad" else DEFAULT_TEST_FAILURE_MSG,
            exit_success = MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.SIGVERIFY.BAD_ENCODED_MSG)) if a["desc"] == b["desc"] and a["desc"] == "bad" else MSG_PASS,
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        ),
        key = "multislot",
        ot_flash_binary = ":boot_policy_valid_img_a_{}_b_{}".format(
            a["desc"],
            b["desc"],
        ),
        targets = ["cw310_rom"],
    )
    for lc_state, lc_state_val in get_lc_items()
    for a in BOOT_POLICY_VALID_CASES
    for b in BOOT_POLICY_VALID_CASES
]

test_suite(
    name = "rom_e2e_boot_policy_valid",
    tags = ["manual"],
    tests = [
        "boot_policy_valid_{}_a_{}_b_{}".format(
            lc_state,
            a["desc"],
            b["desc"],
        )
        for lc_state, _ in get_lc_items()
        for a in BOOT_POLICY_VALID_CASES
        for b in BOOT_POLICY_VALID_CASES
    ],
)

# Apply an overlay that disables ROM execution on top of the base OTP configs.
[
    otp_image(
        name = "img_{}_exec_disabled".format(lc_state),
        src = "//hw/ip/otp_ctrl/data:otp_json_" + lc_state,
        overlays = STD_OTP_OVERLAYS + ["//hw/ip/otp_ctrl/data:otp_json_exec_disabled"],
        visibility = ["//visibility:private"],
    )
    for lc_state, _ in get_lc_items()
]

# Splice each execution-disabled OTP image into the ROM bitstream.
[
    bitstream_splice(
        name = "rom_otp_{}_exec_disabled".format(lc_state),
        src = "//hw/bitstream:rom",
        data = "img_{}_exec_disabled".format(lc_state),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = [
            "manual",
            "vivado",
        ],
        update_usr_access = True,
        visibility = ["//visibility:private"],
    )
    for lc_state, _ in get_lc_items()
]

SRAM_JTAG_INJECTION_GDB_SCRIPT = """
        target extended-remote :3333

        echo :::: Send OpenOCD the 'reset halt' command.\\n
        monitor reset halt


        # Mitigate flakiness from the watchdog timer. Prior to connecting
        # OpenOCD and GDB, the device is executing normally. The ROM has
        # probably already started up and configured the watchdog timer. This is
        # a problem; if the timer fires while we're connected, the interrupt
        # will steal control away from the debugger and cause this test to fail.
        # Thus, we need to disable the watchdog timer as quickly as possible to
        # minimize the chances of it firing.
        #
        # The proper solution would be to disable ROM execution by provisioning
        # with an OTP image that has CREATOR_SW_CFG_ROM_EXEC_EN set to zero.
        #
        # Initialize and disable the watchdog timer per aon_timer docs [1]. The
        # hardcoded addresses were computed by adding REG_OFFSET values from
        # //hw/ip/aon_timer/data:aon_timer_regs to the base address
        # TOP_EARLGREY_AON_TIMER_AON_BASE_ADDR.
        #
        # [1]: https://docs.opentitan.org/hw/ip/aon_timer/doc/#initialization

        echo :::: Disable the watchdog timer.\\n
        monitor mdw 0x40470014
        monitor mww 0x40470014 0
        echo :::: Reset WDOG_COUNT.\\n
        monitor mdw 0x40470020
        monitor mww 0x40470020 0
        echo :::: Clear the interrupt (if any) by writing to INTR_STATE.\\n
        monitor mdw 0x40470024
        monitor mww 0x40470024 0


        # Before transferring the SRAM program to the device, we must configure
        # the PMP unit to enable writing to and executing from SRAM. Due to
        # implementation details of OpenTitan's hardware debug module, we cannot
        # set pmpcfg* registers to arbitrary values [1]. However, we can safely
        # modify unused PMP configuration registers. Thankfully, pmp0cfg (the
        # lowest byte of CSR pmpcfg0) is unused and has the highest priority.
        #
        # In more detail, the problem is that our debug module implements the
        # "Access Register" abstract command by assembling instructions in the
        # program buffer and then executing the buffer. If one of those
        # instructions clobbers the PMP configuration register that allows
        # execution from the program buffer, subsequent instruction fetches will
        # generate exceptions.
        #
        # Debug module concepts like abstract commands and the program buffer
        # buffer are defined in "RISC-V External Debug Support Version 0.13.2"
        # [2]. OpenTitan's (vendored-in) implementation lives in
        # //hw/vendor/pulp_riscv_dbg.
        #
        # [1]: https://github.com/lowRISC/opentitan/issues/14978
        # [2]: https://riscv.org/wp-content/uploads/2019/03/riscv-debug-release.pdf

        echo :::: Configure the PMP unit.\\n
        monitor reg pmpcfg0
        # Write "L NAPOT X W R" to pmp{0,1,2,3}cfg in pmpcfg0. Crucially, this
        # value is no less permissive than whatever the current value is.
        monitor reg pmpcfg0 0x9f9f9f9f
        monitor reg pmpaddr0 0xffffffff

        echo :::: Value of CREATOR_SW_CFG_ROM_EXEC_EN.\\n
        monitor mdw 0x40131108

        echo :::: Load the SRAM program onto the device and check integrity.\\n
        file sram_program.elf
        load sram_program.elf
        compare-sections

        echo :::: Update registers before calling functions.\\n
        set $sp = _stack_end
        set $gp = __global_pointer$
        info registers

        # When testing SRAM execution, we want to be sure the code is running
        # out of SRAM and not the instruction cache.
        echo :::: Invalidate the icache.\\n
        print icache_invalidate()

        echo :::: Call sram_main().\\n
        print sram_main()

        echo :::: Done.\\n
"""

[
    opentitan_gdb_fpga_cw310_test(
        name = "sram_program_fpga_cw310_test_otp_" + lc_state,
        timeout = "short",
        exit_success_pattern = "sram_program\\.c:\\d+\\] PC: 0x1000[0-2][0-9a-f]{3}, SRAM: \\[0x10000000, 0x10020000\\)",
        gdb_script = SRAM_JTAG_INJECTION_GDB_SCRIPT,
        gdb_script_symlinks = {
            "//sw/device/examples/sram_program:sram_program_fpga_cw310.elf": "sram_program.elf",
        },
        rom_bitstream = ":rom_otp_{}_exec_disabled".format(lc_state),
        rom_kind = "Rom",
        tags = [
            "cw310_rom",
            "vivado",
        ],
    )
    for lc_state, _ in get_lc_items(
        CONST.LCV.TEST_UNLOCKED0,
        CONST.LCV.DEV,
        CONST.LCV.RMA,
    )
]

test_suite(
    name = "rom_e2e_jtag_inject_tests",
    tags = ["manual"],
    tests = [
        "sram_program_fpga_cw310_test_otp_" + lc_state
        for lc_state, _ in get_lc_items(
            CONST.LCV.TEST_UNLOCKED0,
            CONST.LCV.DEV,
            CONST.LCV.RMA,
        )
    ],
)

[
    opentitan_functest(
        name = "epmp_init_otp_" + lc_state,
        srcs = ["epmp_init_test.c"],
        cw310 = cw310_params(
            bitstream = "//hw/bitstream:rom_otp_" + lc_state,
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        ),
        key = LC_KEY_TYPES[lc_state_val][0],
        local_defines = [
            "EXPECT_DEBUG={}".format(1 if lc_state_val in [
                CONST.LCV.TEST_UNLOCKED0,
                CONST.LCV.DEV,
                CONST.LCV.RMA,
            ] else 0),
        ],
        targets = [
            "cw310_rom",
            "verilator",
        ],
        verilator = verilator_params(
            timeout = "eternal",
            otp = "//hw/ip/otp_ctrl/data:img_" + lc_state,
            rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
        ),
        deps = [
            "//hw/top_earlgrey/sw/autogen:top_earlgrey",
            "//sw/device/lib/base:csr",
            "//sw/device/lib/dif:lc_ctrl",
            "//sw/device/lib/runtime:log",
            "//sw/device/lib/testing:lc_ctrl_testutils",
            "//sw/device/lib/testing/test_framework:check",
            "//sw/device/lib/testing/test_framework:ottf_main",
            "//sw/device/lib/testing/test_framework:status",
            "//sw/device/silicon_creator/lib:epmp_defs",
        ],
    )
    for lc_state, lc_state_val in get_lc_items()
]

test_suite(
    name = "rom_e2e_epmp_init",
    tags = ["manual"],
    tests = ["epmp_init_otp_" + lc_state for lc_state, _ in get_lc_items()],
)

[
    opentitan_gdb_fpga_cw310_test(
        name = "debug_disallowed_in_prod_fpga_cw310_test_otp_" + lc_state,
        timeout = "short",
        expect_debug_disallowed = lc_state_val in [
            CONST.LCV.PROD,
            CONST.LCV.PROD_END,
        ],
        gdb_script = """
            target extended-remote :3333

            echo :::: Send OpenOCD the 'reset halt' command.\\n
            monitor reset halt

            echo :::: Load ROM symbols into GDB.\\n
            file rom.elf

            print $pc
        """,
        gdb_script_symlinks = {
            "//sw/device/silicon_creator/rom:rom_with_fake_keys_fpga_cw310.elf": "rom.elf",
        },
        rom_bitstream = ":rom_otp_{}_exec_disabled".format(lc_state),
        rom_kind = "Rom",
        tags = [
            "cw310_rom",
            "vivado",
        ] + maybe_skip_in_ci(lc_state_val),
    )
    for lc_state, lc_state_val in get_lc_items(
        CONST.LCV.PROD,
        CONST.LCV.PROD_END,
        CONST.LCV.RMA,
    )
]

test_suite(
    name = "rom_e2e_debug_disallowed_in_prod_tests",
    tags = ["manual"],
    tests = [
        "debug_disallowed_in_prod_fpga_cw310_test_otp_" + lc_state
        for lc_state, _ in get_lc_items(
            CONST.LCV.PROD,
            CONST.LCV.PROD_END,
            CONST.LCV.RMA,
        )
    ],
)

[
    opentitan_gdb_fpga_cw310_test(
        name = "asm_interrupt_handler_fpga_cw310_test_otp_" + lc_state,
        timeout = "short",
        gdb_script = """
            target extended-remote :3333

            echo :::: Send OpenOCD the 'reset halt' command.\\n
            monitor reset halt

            echo :::: Load ROM symbols into GDB.\\n
            file rom.elf

            echo :::: Set breakpoint on exception handler.\\n
            break _asm_exception_handler

            echo :::: Attempt to trigger an exception.\\n
            set $pc = 0
            continue
            printf ":::: PC=%p. Expected PC=%p.\\n", $pc, _asm_exception_handler

            if $pc == _asm_exception_handler
                echo :::: Test passed!\\n
                quit 0
            else
                echo :::: Test failed!\\n
                quit 1
            end
        """,
        gdb_script_symlinks = {
            "//sw/device/silicon_creator/rom:rom_with_fake_keys_fpga_cw310.elf": "rom.elf",
        },
        rom_bitstream = ":rom_otp_{}_exec_disabled".format(lc_state),
        rom_kind = "Rom",
        tags = [
            "cw310_rom",
            "vivado",
        ] + maybe_skip_in_ci(lc_state_val),
    )
    for lc_state, lc_state_val in get_lc_items(
        CONST.LCV.TEST_UNLOCKED0,
        CONST.LCV.DEV,
        CONST.LCV.RMA,
    )
]

test_suite(
    name = "rom_e2e_asm_interrupt_handler",
    tags = ["manual"],
    tests = [
        "asm_interrupt_handler_fpga_cw310_test_otp_" + lc_state
        for lc_state, _ in get_lc_items(
            CONST.LCV.TEST_UNLOCKED0,
            CONST.LCV.DEV,
            CONST.LCV.RMA,
        )
    ],
)

[
    opentitan_gdb_fpga_cw310_test(
        name = "shutdown_exception_asm_otp_" + lc_state,
        timeout = "short",
        gdb_expect_output_sequence = [
            ":::: About to reset.",
            "unable to resume hart 0",
        ],
        gdb_script = """
            target extended-remote :3333

            echo :::: Send OpenOCD the 'reset halt' command.\\n
            monitor reset halt

            echo :::: Load ROM symbols into GDB.\\n
            file rom.elf

            echo :::: Set breakpoint on exception handler.\\n
            break _asm_exception_handler

            echo :::: Set PC to start of main SRAM.\\n
            set $pc = 0x10000000
            continue
            printf ":::: PC=%p. Expected PC=%p.\\n", $pc, _asm_exception_handler
            if $pc != _asm_exception_handler
                quit 1
            end

            echo :::: About to reset.\\n
            continue

            # Not reached.
            quit 123
        """,
        gdb_script_symlinks = {
            "//sw/device/silicon_creator/rom:rom_with_fake_keys_fpga_cw310.elf": "rom.elf",
        },
        rom_bitstream = ":rom_otp_{}_exec_disabled".format(lc_state),
        rom_kind = "Rom",
        tags = [
            "cw310_rom",
            "vivado",
        ] + maybe_skip_in_ci(lc_state_val),
    )
    for lc_state, lc_state_val in get_lc_items(
        CONST.LCV.TEST_UNLOCKED0,
        CONST.LCV.DEV,
        CONST.LCV.RMA,
    )
]

test_suite(
    name = "rom_e2e_shutdown_exception_asm",
    tags = ["manual"],
    tests = [
        "shutdown_exception_asm_otp_" + lc_state
        for lc_state, _ in get_lc_items(
            CONST.LCV.TEST_UNLOCKED0,
            CONST.LCV.DEV,
            CONST.LCV.RMA,
        )
    ],
)

# Ensure that the watchdog restarts the ROM even when the bite threshold has
# been artificially inflated.
[
    opentitan_gdb_fpga_cw310_test(
        name = "rom_e2e_asm_watchdog_bark_fpga_cw310_test_otp_" + lc_state,
        timeout = "short",
        gdb_script = """
            target extended-remote :3333

            echo :::: Send OpenOCD the 'reset halt' command.\\n
            monitor reset halt

            echo :::: Load ROM symbols into GDB.\\n
            file rom.elf

            echo :::: Run until we check whether ROM execution is enabled.\\n
            break kRomStartBootMaybeHalt
            continue

            printf ":::: PC=%p. Expected PC=%p.\\n", $pc, kRomStartBootMaybeHalt
            if $pc != kRomStartBootMaybeHalt
                quit 42
            end

            echo :::: Pretend execution is enabled.\\n
            set $pc = kRomStartBootExecEn

            break kRomStartStoreT1ToBiteThold
            continue
            printf ":::: PC=%p. Expected PC=%p.\\n", $pc, kRomStartStoreT1ToBiteThold
            if $pc != kRomStartStoreT1ToBiteThold
                quit 43
            end

            # Set the bite threshold to UINT32_MAX. We want to exercise that the
            # bark causes control to reach the interrupt handler.
            set $t1 = 0xffffffff

            echo :::: Run until right after configuring the watchdog timer.\\n
            break kRomStartWatchdogEnabled
            continue

            printf ":::: PC=%p. Expected PC=%p.\\n", $pc, kRomStartWatchdogEnabled
            if $pc != kRomStartWatchdogEnabled
                quit 44
            end

            echo :::: Set breakpoint on NMI handler.\\n
            delete breakpoints
            break _asm_exception_handler

            echo :::: Wait for interrupt.\\n
            set $pc = kRomStartBootMaybeHalt
            echo :::: Continue.\\n
            continue

            printf ":::: PC=%p. Expected PC=%p.\\n", $pc, _asm_exception_handler
            if $pc != _asm_exception_handler
                quit 45
            end
        """,
        gdb_script_symlinks = {
            "//sw/device/silicon_creator/rom:rom_with_fake_keys_fpga_cw310.elf": "rom.elf",
        },
        rom_bitstream = ":rom_otp_{}_exec_disabled".format(lc_state),
        rom_kind = "Rom",
        tags = [
            "cw310_rom",
            "vivado",
        ] + maybe_skip_in_ci(lc_state_val),
    )
    for lc_state, lc_state_val in get_lc_items(
        CONST.LCV.TEST_UNLOCKED0,
        CONST.LCV.DEV,
        CONST.LCV.RMA,
    )
]

# Ensure that the watchdog's bite restarts the ROM.
[
    opentitan_gdb_fpga_cw310_test(
        name = "rom_e2e_asm_watchdog_bite_fpga_cw310_test_otp_" + lc_state,
        timeout = "short",
        gdb_expect_output_sequence = [
            ":::: Wait for interrupt.",
            "Hart 0 unexpectedly reset!",
        ],
        gdb_script = """
            target extended-remote :3333

            echo :::: Send OpenOCD the 'reset halt' command.\\n
            monitor reset halt

            echo :::: Load ROM symbols into GDB.\\n
            file rom.elf

            echo :::: Run until we check whether ROM execution is enabled.\\n
            break kRomStartBootMaybeHalt
            continue

            printf ":::: PC=%p. Expected PC=%p.\\n", $pc, kRomStartBootMaybeHalt
            if $pc != kRomStartBootMaybeHalt
                quit 42
            end

            echo :::: Pretend execution is enabled.\\n
            set $pc = kRomStartBootExecEn

            echo :::: Run until right after configuring the watchdog timer.\\n
            break kRomStartWatchdogEnabled
            continue

            printf ":::: PC=%p. Expected PC=%p.\\n", $pc, kRomStartWatchdogEnabled
            if $pc != kRomStartWatchdogEnabled
                quit 43
            end

            echo :::: Set breakpoint on NMI handler.\\n
            delete breakpoints
            break _asm_exception_handler

            echo :::: Wait for interrupt.\\n
            set $pc = kRomStartBootMaybeHalt
            echo :::: Continue.\\n
            continue

            # Not reached.
            quit 123
        """,
        gdb_script_symlinks = {
            "//sw/device/silicon_creator/rom:rom_with_fake_keys_fpga_cw310.elf": "rom.elf",
        },
        rom_bitstream = ":rom_otp_{}_exec_disabled".format(lc_state),
        rom_kind = "Rom",
        tags = [
            "cw310_rom",
            "vivado",
        ] + maybe_skip_in_ci(lc_state_val),
    )
    for lc_state, lc_state_val in get_lc_items(
        CONST.LCV.TEST_UNLOCKED0,
        CONST.LCV.DEV,
        CONST.LCV.RMA,
    )
]

test_suite(
    name = "rom_e2e_asm_watchdog",
    tags = ["manual"],
    tests = [
        "rom_e2e_asm_watchdog_" + type + "_fpga_cw310_test_otp_" + lc_state
        for lc_state, lc_state_val in get_lc_items(
            CONST.LCV.TEST_UNLOCKED0,
            CONST.LCV.DEV,
            CONST.LCV.RMA,
        )
        for type in ("bite", "bark")
    ],
)

# Shutdown Redact Test

# Dict that also includes an invalid redaction value for test purposes.
REDACT = structs.to_dict(CONST.SHUTDOWN.REDACT)

REDACT.update({"INVALID": 0x0})

[
    otp_json(
        name = "otp_json_{}_overlay".format(k.lower()),
        partitions = [
            otp_partition(
                name = "OWNER_SW_CFG",
                items = {
                    "OWNER_SW_CFG_ROM_ERROR_REPORTING": hex(v),
                },
            ),
        ],
    )
    for k, v in REDACT.items()
]

[
    otp_image(
        name = "img_{}_{}".format(
            lc_state,
            redact.lower(),
        ),
        src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state),
        overlays = STD_OTP_OVERLAYS + [":otp_json_{}_overlay".format(redact.lower())],
        visibility = ["//visibility:private"],
    )
    for lc_state, _ in get_lc_items()
    for redact in REDACT
]

[
    bitstream_splice(
        name = "bitstream_{}_{}".format(
            lc_state,
            redact.lower(),
        ),
        src = "//hw/bitstream:rom",
        data = ":img_{}_{}".format(
            lc_state,
            redact.lower(),
        ),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"],
        update_usr_access = True,
        visibility = ["//visibility:private"],
    )
    for lc_state, _ in get_lc_items()
    for redact in REDACT
]

[
    opentitan_functest(
        name = "e2e_shutdown_redact_{}_{}".format(
            lc_state,
            redact.lower(),
        ),
        srcs = ["empty_test.c"],
        cw310 = cw310_params(
            bitstream = "bitstream_{}_{}".format(
                lc_state,
                redact.lower(),
            ),
            exit_failure = MSG_PASS,
            exit_success = MSG_TEMPLATE_BFV.format(hex_digits(error_redact(
                CONST.BFV.BOOT_POLICY.BAD_IDENTIFIER,
                lc_state_val,
                redact_val,
            ))),
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        ),
        signed = False,
        targets = ["cw310_rom"],
        deps = [
            "//hw/ip/otp_ctrl/data:otp_ctrl_regs",
            "//sw/device/lib/testing/test_framework:ottf_main",
            "//sw/device/silicon_creator/lib/drivers:lifecycle",
            "//sw/device/silicon_creator/lib/drivers:otp",
        ],
    )
    for lc_state, lc_state_val in get_lc_items()
    for redact, redact_val in REDACT.items()
]

test_suite(
    name = "rom_e2e_shutdown_redact",
    tags = ["manual"],
    tests = [
        "e2e_shutdown_redact_{}_{}".format(
            lc_state,
            redact.lower(),
        )
        for lc_state, _ in get_lc_items()
        for redact in REDACT
    ],
)

[
    opentitan_multislot_flash_binary(
        name = "sigverify_always_img_a_{}_b_{}_{}".format(
            "nothing" if slot == "b" else "bad",
            "nothing" if slot == "a" else "bad",
            key,
        ),
        srcs = {
            ":empty_test_slot_{}_corrupted".format(slot): {
                "key": key,
                "offset": offset,
            },
        },
        devices = [
            "sim_dv",
            "fpga_cw310",
        ],
    )
    for slot, offset in SLOTS.items()
    for key in SIGVERIFY_LC_KEYS
]

[
    opentitan_multislot_flash_binary(
        name = "sigverify_always_img_a_bad_b_bad_{}".format(key),
        srcs = {
            ":empty_test_slot_a_corrupted": {
                "key": key,
                "offset": SLOTS["a"],
            },
            ":empty_test_slot_b_corrupted": {
                "key": key,
                "offset": SLOTS["b"],
            },
        },
        devices = [
            "sim_dv",
            "fpga_cw310",
        ],
    )
    for key in SIGVERIFY_LC_KEYS
]

# Since we cannot feed the `assemble_flash_image` rule that is instantiated by
# the `opentitan_multislot_flash_binary` macro an empty dictionary, we create
# two images with "nothing" in them by created files of all ones, and stitching
# them together.
[
    genrule(
        name = "sigverify_always_img_{}_nothing_{}_bin_signed_{}".format(slot, device, key),
        outs = ["sigverify_always_img_{}_all_ones_{}_bin_signed_{}".format(slot, device, key)],
        cmd_bash = "touch $(OUTS)",
    )
    for slot in SLOTS
    for device in [
        "sim_dv",
        "fpga_cw310",
    ]
    for key in SIGVERIFY_LC_KEYS
]

[
    opentitan_multislot_flash_binary(
        name = "sigverify_always_img_a_nothing_b_nothing_{}".format(key),
        srcs = {
            ":sigverify_always_img_a_nothing": {
                "key": key,
                "offset": SLOTS["a"],
            },
            ":sigverify_always_img_b_nothing": {
                "key": key,
                "offset": SLOTS["b"],
            },
        },
        devices = [
            "sim_dv",
            "fpga_cw310",
        ],
    )
    for key in SIGVERIFY_LC_KEYS
]

[otp_image(
    name = "otp_img_sigverify_always_{}".format(lc_state),
    src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state),
    overlays = STD_OTP_OVERLAYS,
) for lc_state, _ in get_lc_items()]

# Splice OTP images into bitstreams
[
    bitstream_splice(
        name = "bitstream_sigverify_always_{}".format(lc_state),
        src = "//hw/bitstream:rom",
        data = ":otp_img_sigverify_always_{}".format(lc_state),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        update_usr_access = True,
    )
    for lc_state, lc_state_val in get_lc_items()
]

SIGVERIFY_BAD_CASES = [
    {
        "a": "nothing",
        "b": "bad",
        "expected_bfv": hex_digits(CONST.BFV.SIGVERIFY.BAD_ENCODED_MSG),
    },
    {
        "a": "bad",
        "b": "nothing",
        "expected_bfv": hex_digits(CONST.BFV.SIGVERIFY.BAD_ENCODED_MSG),
    },
    {
        "a": "bad",
        "b": "bad",
        "expected_bfv": hex_digits(CONST.BFV.SIGVERIFY.BAD_ENCODED_MSG),
    },
    {
        "a": "nothing",
        "b": "nothing",
        "expected_bfv": hex_digits(CONST.BFV.BOOT_POLICY.BAD_IDENTIFIER),
    },
]

[
    opentitan_functest(
        name = "sigverify_always_{}_a_{}_b_{}".format(
            lc_state,
            case["a"],
            case["b"],
        ),
        cw310 = cw310_params(
            bitstream = ":bitstream_sigverify_always_{}".format(lc_state),
            exit_failure = MSG_PASS,
            exit_success = MSG_TEMPLATE_BFV_LCV.format(
                case["expected_bfv"],
                hex_digits(lc_state_val),
            ),
            otp = ":otp_img_sigverify_always_{}".format(lc_state),
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        ),
        dv = dv_params(
            otp = ":otp_img_sigverify_always_{}".format(lc_state),
            rom = "//sw/device/silicon_creator/rom:rom_with_fake_keys",
        ),
        key = "multislot",
        ot_flash_binary = ":sigverify_always_img_a_{}_b_{}_{}".format(
            case["a"],
            case["b"],
            SIGVERIFY_LCS_2_VALID_KEY[lc_state],
        ),
        targets = [
            "dv",
            "cw310_rom",
        ],
    )
    for case in SIGVERIFY_BAD_CASES
    for lc_state, lc_state_val in get_lc_items()
]

test_suite(
    name = "sigverify_always",
    tags = ["manual"],
    tests = [
        "sigverify_always_{}_a_{}_b_{}".format(
            lc_state,
            case["a"],
            case["b"],
        )
        for case in SIGVERIFY_BAD_CASES
        for lc_state, _ in get_lc_items()
    ],
)

[
    otp_image(
        name = "otp_img_sigverify_key_type_{}".format(lc_state),
        src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state),
        overlays = STD_OTP_OVERLAYS,
    )
    for lc_state, _ in get_lc_items()
]

[
    bitstream_splice(
        name = "bitstream_sigverify_key_type_{}".format(
            lc_state,
        ),
        src = "//hw/bitstream:rom",
        data = ":otp_img_sigverify_key_type_{}".format(
            lc_state,
        ),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        update_usr_access = True,
        visibility = ["//visibility:private"],
    )
    for lc_state, lc_state_val in get_lc_items()
]

# list of the keys to test when doing a full key set test
SIGVERIFY_FULL_KEY_SET = FAKE_ALL_KEYS

[
    opentitan_functest(
        name = "sigverify_key_type_{}_{}".format(
            lc_state,
            key,
        ),
        cw310 = cw310_params(
            bitstream = ":bitstream_sigverify_key_type_{}".format(lc_state),
            exit_failure = MSG_PASS if key not in LC_KEY_TYPES[lc_state_val] else MSG_TEMPLATE_BFV_LCV.format(
                hex_digits(CONST.BFV.SIGVERIFY.BAD_KEY),
                hex_digits(lc_state_val),
            ),
            exit_success = MSG_PASS if key in LC_KEY_TYPES[lc_state_val] else MSG_TEMPLATE_BFV_LCV.format(
                hex_digits(CONST.BFV.SIGVERIFY.BAD_KEY),
                hex_digits(lc_state_val),
            ),
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        ),
        key = key,
        ot_flash_binary = "empty_test_slot_a",
        targets = [
            "cw310_rom",
        ],
    )
    for lc_state, lc_state_val in get_lc_items()
    for key in SIGVERIFY_FULL_KEY_SET
]

test_suite(
    name = "rom_e2e_sigverify_key_type",
    tags = ["manual"],
    tests = [
        "sigverify_key_type_{}_{}".format(
            lc_state,
            key,
        )
        for lc_state, _ in get_lc_items()
        for key in SIGVERIFY_FULL_KEY_SET
    ],
)

otp_json(
    name = "otp_json_sigverify_key_validity",
    partitions = [
        otp_partition(
            name = "CREATOR_SW_CFG",
            items = {
                "CREATOR_SW_CFG_SIGVERIFY_RSA_KEY_EN": "0x4b4b4b4b4bff004b",
            },
        ),
    ],
)

[
    otp_image(
        name = "otp_img_sigverify_key_validity_{}".format(lc_state),
        src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state),
        overlays = STD_OTP_OVERLAYS + [":otp_json_sigverify_key_validity"],
    )
    for lc_state, _ in get_lc_items()
]

[
    bitstream_splice(
        name = "bitstream_sigverify_key_validity_{}".format(
            lc_state,
        ),
        src = "//hw/bitstream:rom",
        data = ":otp_img_sigverify_key_validity_{}".format(
            lc_state,
        ),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        update_usr_access = True,
        visibility = ["//visibility:private"],
    )
    for lc_state, lc_state_val in get_lc_items()
]

[
    opentitan_functest(
        name = "sigverify_key_validity_{}_{}".format(
            lc_state,
            key,
        ),
        cw310 = cw310_params(
            bitstream = ":bitstream_sigverify_key_validity_{}".format(lc_state),
            exit_failure = MSG_PASS if lc_state_val != CONST.LCV.TEST_UNLOCKED0 else MSG_TEMPLATE_BFV_LCV.format(
                hex_digits(CONST.BFV.SIGVERIFY.BAD_KEY),
                hex_digits(lc_state_val),
            ),
            exit_success = MSG_TEMPLATE_BFV_LCV.format(
                hex_digits(CONST.BFV.SIGVERIFY.BAD_KEY),
                hex_digits(lc_state_val),
            ) if lc_state_val != CONST.LCV.TEST_UNLOCKED0 else MSG_PASS,
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        ),
        key = key,
        ot_flash_binary = "empty_test_slot_a",
        targets = [
            "cw310_rom",
        ],
    )
    for lc_state, lc_state_val in get_lc_items()
    for key in LC_KEY_TYPES[lc_state_val]
]

test_suite(
    name = "rom_e2e_sigverify_key_validity",
    tags = ["manual"],
    tests = [
        "sigverify_key_validity_{}_{}".format(
            lc_state,
            key,
        )
        for lc_state, lc_state_val in get_lc_items()
        for key in LC_KEY_TYPES[lc_state_val]
    ],
)

# Sigverify usage constraint tests
_test_device_id = [
    "0xa0a1a2a3",  # Least-significant word
    "0x12345678",
    "0x00000003",
    "0xabababab",
    "0xcdcdcdcd",
    "0x01010101",
    "0x10101010",
    "0xf0f1f2f3",  # Most-significant word
]

_test_manuf_states = {
    "creator": "0xfedcba98",
    "owner": "0x12345678",
}

# Generate OTP image with a specific device ID, creator manufacturing state,
# and owner manufacturing state
_test_device_id_joined = "0x" + "".join([word[2:] for word in reversed(_test_device_id)])

otp_json(
    name = "otp_json_set_usage_constraint_params_overlay",
    partitions = [
        otp_partition(
            name = "HW_CFG",
            items = {"DEVICE_ID": _test_device_id_joined},
        ),
        otp_partition(
            name = "CREATOR_SW_CFG",
            items = {"CREATOR_SW_CFG_MANUF_STATE": _test_manuf_states["creator"]},
        ),
        otp_partition(
            name = "OWNER_SW_CFG",
            items = {"OWNER_SW_CFG_MANUF_STATE": _test_manuf_states["owner"]},
        ),
    ],
    visibility = ["//visibility:private"],
)

[otp_image(
    name = "otp_img_sigverify_usage_constraints_{}".format(lc_state),
    src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state),
    overlays = STD_OTP_OVERLAYS + [":otp_json_set_usage_constraint_params_overlay"],
    visibility = ["//visibility:private"],
) for lc_state, _ in get_lc_items()]

[bitstream_splice(
    name = "bitstream_sigverify_usage_constraints_{}".format(lc_state),
    src = "//hw/bitstream:rom",
    data = ":otp_img_sigverify_usage_constraints_{}".format(lc_state),
    meminfo = "//hw/bitstream:otp_mmi",
    tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
    update_usr_access = True,
    visibility = ["//visibility:private"],
) for lc_state, lc_state_val in get_lc_items()]

_SIGVERIFY_FAIL_MSG = MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.SIGVERIFY.BAD_ENCODED_MSG))

device_id_test_cases = [
    {
        "name": "device_id_match",
        "manifest": {
            "selector_bits": "0xff",
            "device_id": _test_device_id,
        },
        "bitstream": ":bitstream_sigverify_usage_constraints_rma",
        "exit_success": DEFAULT_TEST_SUCCESS_MSG,
        "exit_failure": _SIGVERIFY_FAIL_MSG,
        "lc_state_val": CONST.LCV.RMA,
    },
    {
        "name": "device_id_no_match",
        "manifest": {
            "selector_bits": "0xff",
            "device_id": ["0xbad"] * 8,
        },
        "bitstream": ":bitstream_sigverify_usage_constraints_rma",
        "exit_success": _SIGVERIFY_FAIL_MSG,
        "exit_failure": DEFAULT_TEST_SUCCESS_MSG,
        "lc_state_val": CONST.LCV.RMA,
    },
    {
        "name": "device_id_family_match",
        "manifest": {
            # Select words 0, 3, and 5 to match on:
            # 0b0010_1001 = 0x29
            "selector_bits": "0x29",
            "device_id": [
                _test_device_id[0],
                hex(CONST.DEFAULT_USAGE_CONSTRAINTS),
                hex(CONST.DEFAULT_USAGE_CONSTRAINTS),
                _test_device_id[3],
                hex(CONST.DEFAULT_USAGE_CONSTRAINTS),
                _test_device_id[5],
                hex(CONST.DEFAULT_USAGE_CONSTRAINTS),
                hex(CONST.DEFAULT_USAGE_CONSTRAINTS),
            ],
        },
        "bitstream": ":bitstream_sigverify_usage_constraints_rma",
        "exit_success": DEFAULT_TEST_SUCCESS_MSG,
        "exit_failure": _SIGVERIFY_FAIL_MSG,
        "lc_state_val": CONST.LCV.RMA,
    },
    {
        "name": "device_id_family_no_match",
        "manifest": {
            # Select words 0, 3, and 5 to match on:
            # 0b0010_1001 = 0x29
            "selector_bits": "0x29",
            "device_id": [
                "0xbad",
                hex(CONST.DEFAULT_USAGE_CONSTRAINTS),
                hex(CONST.DEFAULT_USAGE_CONSTRAINTS),
                "0xbad",
                hex(CONST.DEFAULT_USAGE_CONSTRAINTS),
                "0xbad",
                hex(CONST.DEFAULT_USAGE_CONSTRAINTS),
                hex(CONST.DEFAULT_USAGE_CONSTRAINTS),
            ],
        },
        "bitstream": ":bitstream_sigverify_usage_constraints_rma",
        "exit_success": _SIGVERIFY_FAIL_MSG,
        "exit_failure": DEFAULT_TEST_SUCCESS_MSG,
        "lc_state_val": CONST.LCV.RMA,
    },
]

lc_state_test_cases = [
    {
        "name": "lc_state_{}_{}".format(
            lc_state,
            "match" if match_case else "no_match",
        ),
        # Note: the manifest value for a given life-cycle state is determined
        # by CONST.LCV_SW instead of CONST.LCV. These two structs have slightly
        # different mappings for the TEST_* LC state, so lc_hw_to_sw is used to
        # convert from the names in CONST.LCV to those in CONST.LCV_SW before
        # performing the lookup.
        "manifest": {
            "selector_bits": "0x400",
            "life_cycle_state": hex(lcv_hw_to_sw(lc_state_val)) if match_case else "0",
        },
        "bitstream": ":bitstream_sigverify_usage_constraints_{}".format(lc_state),
        "exit_success": DEFAULT_TEST_SUCCESS_MSG if match_case else _SIGVERIFY_FAIL_MSG,
        "exit_failure": _SIGVERIFY_FAIL_MSG if match_case else DEFAULT_TEST_SUCCESS_MSG,
        "lc_state_val": lc_state_val,
    }
    for lc_state, lc_state_val in get_lc_items()
    for match_case in (True, False)
]

manuf_state_test_cases = [
    {
        "name": "manuf_state_{}_{}".format(
            entity,
            "match" if match_case else "no_match",
        ),
        "manifest": {
            "selector_bits": "0x100" if entity == "creator" else "0x200",
            "manuf_state_{}".format(entity): "{}".format(_test_manuf_states[entity]) if match_case else "0",
        },
        "bitstream": ":bitstream_sigverify_usage_constraints_rma",
        "exit_success": DEFAULT_TEST_SUCCESS_MSG if match_case else _SIGVERIFY_FAIL_MSG,
        "exit_failure": _SIGVERIFY_FAIL_MSG if match_case else DEFAULT_TEST_SUCCESS_MSG,
        "lc_state_val": CONST.LCV.RMA,
    }
    for entity in ("creator", "owner")
    for match_case in (True, False)
]

# The all-constraints case is tested against all LC states. For each LC state,
# we try all 5 LC state settings in the manifest and ensure that only one
# boots successfully.
all_constr_test_cases = [
    {
        "name": "all_constraints_mf_lc_{}_bs_lc_{}".format(
            mf_lc_state.lower(),
            bs_lc_state,
        ),
        "manifest": {
            "selector_bits": "0x7ff",
            "device_id": _test_device_id,
            "life_cycle_state": hex(mf_lc_val),
            "manuf_state_creator": _test_manuf_states["creator"],
            "manuf_state_owner": _test_manuf_states["owner"],
        },
        "bitstream": ":bitstream_sigverify_usage_constraints_{}".format(bs_lc_state),
        "exit_success": DEFAULT_TEST_SUCCESS_MSG if mf_lc_val == lcv_hw_to_sw(bs_lc_val) else _SIGVERIFY_FAIL_MSG,
        "exit_failure": _SIGVERIFY_FAIL_MSG if mf_lc_val == lcv_hw_to_sw(bs_lc_val) else DEFAULT_TEST_SUCCESS_MSG,
        "lc_state_val": bs_lc_val,
    }
    for mf_lc_state, mf_lc_val in structs.to_dict(CONST.LCV_SW).items()
    for bs_lc_state, bs_lc_val in get_lc_items()
]

# Usage constraints that are not selected by the selector_bits must be set to
# MANIFEST_USAGE_CONSTRAINT_UNSELECTED_WORD. These tests check for a failure if
# they are not by setting various fields to otherwise valid values while
# setting the selector_bits to 0.
invalid_unselected_word_cases = [
    {
        "name": "invalid_unselected_{}".format(field),
        "manifest": {
            field: field_val,
            "selector_bits": "0",
            "selector_mismatch_is_failure": False,
        },
        "bitstream": ":bitstream_sigverify_usage_constraints_rma",
        "exit_success": _SIGVERIFY_FAIL_MSG,
        "exit_failure": DEFAULT_TEST_SUCCESS_MSG,
        "lc_state_val": CONST.LCV.RMA,
    }
    for field, field_val in [
        ("device_id", _test_device_id),
        (
            "life_cycle_state",
            hex(CONST.LCV_SW.RMA),
        ),
        (
            "manuf_state_creator",
            _test_manuf_states["creator"],
        ),
        (
            "manuf_state_owner",
            _test_manuf_states["owner"],
        ),
    ]
]

test_cases = device_id_test_cases + lc_state_test_cases + manuf_state_test_cases + all_constr_test_cases + invalid_unselected_word_cases

[opentitan_functest(
    name = "sigverify_usage_constraint_{}".format(t["name"]),
    srcs = ["empty_test.c"],
    cw310 = cw310_params(
        bitstream = t["bitstream"],
        exit_failure = t["exit_failure"],
        exit_success = t["exit_success"],
        tags = ["vivado"] + maybe_skip_in_ci(t["lc_state_val"]),
    ),
    manifest = manifest(
        dict(
            t["manifest"],
            name = "sigverify_usage_constraint_manifest_{}".format(t["name"]),
            address_translation = hex(CONST.FALSE),
            identifier = hex(CONST.ROM_EXT),
        ),
    ),
    signed = True,
    targets = ["cw310_rom"],
    deps = [
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:otp",
    ],
) for t in test_cases]

test_suite(
    name = "rom_e2e_sigverify_usage_constraints",
    tags = ["manual"],
    tests = ["sigverify_usage_constraint_{}".format(t["name"]) for t in test_cases],
)

[
    opentitan_gdb_fpga_cw310_test(
        name = "rom_e2e_debug_test_otp_" + lc_state,
        timeout = "short",
        exit_success_pattern = "OK!GDB-OK(?s:.*)BFV:0142500d",
        gdb_expect_output_sequence = [
            ":::: GDB script complete.",
            "Hart 0 unexpectedly reset!",
        ],
        gdb_script = """
            define assert_pc
                printf ":::: PC=%p. Expected PC=%p.\\n", $pc, $arg0
                if $pc != $arg0
                    quit 1
                end
            end

            target extended-remote :3333

            echo :::: Send OpenOCD the 'reset halt' command.\\n
            monitor reset halt

            echo :::: Load ROM symbols into GDB.\\n
            file rom.elf

            # Immediately after reset, we should be sitting on the Ibex reset
            # handler, the 33rd entry in the interrupt vector.
            set $ibex_reset_handler = _rom_interrupt_vector_asm + 32 * 4
            assert_pc $ibex_reset_handler

            # Executing the `j _rom_start_boot` instruction should take us
            # to _rom_start_boot.
            stepi
            assert_pc _rom_start_boot

            echo :::: Run until we check whether ROM execution is enabled.\\n
            break kRomStartBootMaybeHalt
            continue
            assert_pc kRomStartBootMaybeHalt

            # Use three of four hardware breakpoints. Leave one unused so we can
            # use `call` and `finish`. (See RvCoreIbexDbgHwBreakNum in
            # hw/top_earlgrey/data/top_earlgrey.hjson.)
            echo :::: Set all but one available breakpoints.\\n
            # Set a breakpoint at the actual address of rom_main(), without
            # trying to skip the function prologue.
            break *rom_main
            break *uart_init

            echo :::: Pretend execution is enabled.\\n
            set $pc = kRomStartBootExecEn

            echo :::: Continue until watchdog config.\\n
            break kRomStartWatchdogEnabled
            continue

            echo :::: Disable watchdog config.\\n
            set {{int}}{watchdog_ctrl_reg_addr} = 0
            delete 4

            echo :::: Continue until rom_main.\\n
            continue
            assert_pc rom_main

            echo :::: Continue until uart_init.\\n
            continue
            assert_pc uart_init

            echo :::: Finish uart_init.\\n
            finish

            echo :::: Read and write GPRs.\\n
            {gpr_copy_commands}
            {gpr_set_commands}
            {gpr_restore_commands}

            echo :::: Read selected CSRs.\\n
            {csr_copy_commands}
            {csr_set_commands}
            {csr_restore_commands}

            echo :::: Read and write memory (both SRAM and device).\\n
            # See hw/top_earlgrey/sw/autogen/top_earlgrey_memory.h
            set $sram_base = 0x10000000
            set $sram_len = 0x00008000
            x/16xb $sram_base
            x/16xb $sram_base + ($sram_len / 2)
            x/16xb $sram_base + $sram_len - 16

            echo :::: Manually write bytes to UART0.\\n
            set $uart0_base = 0x40000000
            set $uart_wdata = 0x1c
            print *(uint32_t*)($uart0_base + $uart_wdata) = 'O'
            print *(uint32_t*)($uart0_base + $uart_wdata) = 'K'
            print *(uint32_t*)($uart0_base + $uart_wdata) = '!'

            echo :::: Execute code from GDB with `call` command.\\n
            call uart_putchar('G')
            call uart_putchar('D')
            call uart_putchar('B')
            call uart_putchar('-')
            call uart_putchar('O')
            call uart_putchar('K')
            call uart_putchar('\\r')
            call uart_putchar('\\n')

            echo :::: GDB script complete.\\n
            continue
        """.format(
            csr_copy_commands = gdb_commands_copy_registers(get_gdb_readable_csr_names()),
            csr_restore_commands = gdb_commands_restore_registers(get_gdb_settable_csr_names()),
            csr_set_commands = gdb_commands_set_registers(
                "0x89abcdef",
                get_gdb_settable_csr_names(),
            ),
            gpr_copy_commands = gdb_commands_copy_registers(IBEX_GPRS),
            gpr_restore_commands = gdb_commands_restore_registers(IBEX_GPRS),
            gpr_set_commands = gdb_commands_set_registers("0x89abcdef", IBEX_GPRS),
            watchdog_ctrl_reg_addr = "0x40470014",
        ),
        gdb_script_symlinks = {
            "//sw/device/silicon_creator/rom:rom_with_fake_keys_fpga_cw310.elf": "rom.elf",
        },
        rom_bitstream = ":rom_otp_{}_exec_disabled".format(lc_state),
        rom_kind = "Rom",
        tags = [
            "cw310_rom",
            "exclusive",
            "vivado",
        ] + maybe_skip_in_ci(lc_state_val),
    )
    for lc_state, lc_state_val in get_lc_items(
        CONST.LCV.TEST_UNLOCKED0,
        CONST.LCV.DEV,
        CONST.LCV.RMA,
    )
]

test_suite(
    name = "rom_e2e_debug_test",
    tags = ["manual"],
    tests = [
        "rom_e2e_debug_test_otp_" + lc_state
        for lc_state, _ in get_lc_items(
            CONST.LCV.TEST_UNLOCKED0,
            CONST.LCV.DEV,
            CONST.LCV.RMA,
        )
    ],
)

opentitan_flash_binary(
    name = "rom_ext_upgrade_test",
    srcs = ["rom_ext_upgrade_test.c"],
    devices = [
        "fpga_cw310",
    ],
    deps = [
        "//hw/ip/otp_ctrl/data:otp_ctrl_regs",
        "//sw/device/lib/testing/test_framework:ottf_ld_silicon_creator_slot_a",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib:boot_data",
        "//sw/device/silicon_creator/lib/drivers:lifecycle",
        "//sw/device/silicon_creator/lib/drivers:otp",
        "//sw/device/silicon_creator/lib/drivers:rstmgr",
    ],
)

opentitan_functest(
    name = "rom_ext_upgrade",
    cw310 = cw310_params(
        # Fail if we see version 3, because the test has updated twice, FAIL, version 0 twice, or PASS
        exit_failure = "(min_security_version_rom_ext:[^01])|(FAIL)|((min_security_version_rom_ext:0(?s:.*)){2,})|(PASS)",
        exit_success = "min_security_version_rom_ext:0(?s:.*)min_security_version_rom_ext:1(?s:.*)" + MSG_TEMPLATE_BFV.format(hex_digits(CONST.BFV.BOOT_POLICY.ROLLBACK)),
        test_cmds = [
            "--exec=\"fpga load-bitstream --rom-kind=rom $(rootpath {bitstream})\"",
            "--exec=\"bootstrap --clear-uart=true $(rootpath {flash})\"",
            "--exec=\"console --exit-success={exit_success} --exit-failure={exit_failure}\"",
            "fpga",
            "load-bitstream",
            "$(rootpath {bitstream})",  # This test should clean up after itself
        ],
    ),
    ot_flash_binary = "rom_ext_upgrade_test",
    targets = [
        "cw310_rom",
    ],
)

otp_json(
    name = "otp_json_reset_ret_ram_overlay",
    partitions = [
        otp_partition(
            name = "CREATOR_SW_CFG",
            # Set the mask to 1 << kRstmgrReasonSoftwareRequest to trigger a
            # retention RAM reset after a SW-requested reset
            items = {"CREATOR_SW_CFG_RET_RAM_RESET_MASK": "0x4"},
        ),
    ],
)

otp_image(
    name = "otp_img_reset_ret_ram",
    src = "//hw/ip/otp_ctrl/data:otp_json_rma",
    overlays = STD_OTP_OVERLAYS + [":otp_json_reset_ret_ram_overlay"],
    visibility = ["//visibility:private"],
)

bitstream_splice(
    name = "bitstream_reset_ret_ram",
    src = "//hw/bitstream:rom",
    data = ":otp_img_reset_ret_ram",
    meminfo = "//hw/bitstream:otp_mmi",
    tags = ["vivado"] + maybe_skip_in_ci(CONST.LCV.RMA),
    update_usr_access = True,
    visibility = ["//visibility:private"],
)

opentitan_functest(
    name = "rom_e2e_ret_ram_init",
    srcs = ["rom_e2e_ret_ram_init_test.c"],
    cw310 = cw310_params(
        bitstream = ":bitstream_reset_ret_ram",
        tags = ["vivado"] + maybe_skip_in_ci(CONST.LCV.RMA),
    ),
    signed = True,
    targets = [
        "cw310_rom",
    ],
    deps = [
        "//sw/device/lib/base:memory",
        "//sw/device/lib/dif:rstmgr",
        "//sw/device/lib/runtime:log",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:retention_sram",
        "//sw/device/silicon_creator/lib/drivers:rstmgr",
    ],
)

opentitan_functest(
    name = "rom_e2e_ret_ram_keep",
    srcs = ["rom_e2e_ret_ram_keep_test.c"],
    cw310 = cw310_params(
        bitstream = "//hw/bitstream:rom",
        tags = ["vivado"] + maybe_skip_in_ci(CONST.LCV.RMA),
    ),
    signed = True,
    targets = [
        "cw310_rom",
    ],
    deps = [
        "//hw/top_earlgrey/ip/pwrmgr/data/autogen:pwrmgr_regs",
        "//sw/device/lib/base:memory",
        "//sw/device/lib/dif:aon_timer",
        "//sw/device/lib/dif:pwrmgr",
        "//sw/device/lib/runtime:log",
        "//sw/device/lib/testing:aon_timer_testutils",
        "//sw/device/lib/testing:pwrmgr_testutils",
        "//sw/device/lib/testing/test_framework:check",
        "//sw/device/lib/testing/test_framework:ottf_main",
        "//sw/device/silicon_creator/lib/drivers:retention_sram",
        "//sw/device/silicon_creator/lib/drivers:rstmgr",
    ],
)

manifest({
    "name": "manifest_rom_ext_upgrade_interrupt",
    "address_translation": hex(CONST.FALSE),
    "identifier": hex(CONST.ROM_EXT),
    "security_version": hex(10),
})

otp_json(
    name = "otp_json_rom_ext_upgrade_interrupt",
    partitions = [
        otp_partition(
            name = "CREATOR_SW_CFG",
            items = {
                "CREATOR_SW_CFG_DEFAULT_BOOT_DATA_IN_PROD_EN": hex(CONST.TRUE),
            },
        ),
    ],
)

[
    otp_image(
        name = "otp_img_rom_ext_upgrade_interrupt_{}".format(lc_state),
        src = "//hw/ip/otp_ctrl/data:otp_json_{}".format(lc_state),
        overlays = STD_OTP_OVERLAYS + [":otp_json_rom_ext_upgrade_interrupt"],
        visibility = ["//visibility:private"],
    )
    for lc_state, _ in get_lc_items()
]

[
    bitstream_splice(
        name = "bitstream_rom_ext_upgrade_interrupt_{}".format(
            lc_state,
        ),
        src = "//hw/bitstream:rom",
        data = ":otp_img_rom_ext_upgrade_interrupt_{}".format(
            lc_state,
        ),
        meminfo = "//hw/bitstream:otp_mmi",
        tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        update_usr_access = True,
        visibility = ["//visibility:private"],
    )
    for lc_state, lc_state_val in get_lc_items()
]

[
    opentitan_functest(
        name = "rom_ext_upgrade_interrupt_{}".format(lc_state),
        srcs = ["rom_ext_upgrade_interrupt.c"],
        cw310 = cw310_params(
            bitstream = ":bitstream_rom_ext_upgrade_interrupt_{}".format(lc_state),
            clear_bitstream = True,
            tags = ["vivado"] + maybe_skip_in_ci(lc_state_val),
        ),
        manifest = ":manifest_rom_ext_upgrade_interrupt",
        targets = [
            "cw310_rom",
        ],
        deps = [
            "//sw/device/lib/testing:flash_ctrl_testutils",
            "//sw/device/lib/testing/test_framework:check",
            "//sw/device/lib/testing/test_framework:ottf_main",
            "//sw/device/silicon_creator/lib:boot_data",
            "//sw/device/silicon_creator/lib/drivers:lifecycle",
            "//sw/device/silicon_creator/lib/drivers:rstmgr",
        ],
    )
    for lc_state, lc_state_val in get_lc_items()
]

test_suite(
    name = "rom_e2e_rom_ext_upgrade_interrupt",
    tags = ["manual"],
    tests = ["rom_ext_upgrade_interrupt_{}".format(lc_state) for lc_state, _ in get_lc_items()],
)
